提交 b7c73515 编写于 作者: S Sam Saffron

implemented simple join multimap

上级 4ca04f91
...@@ -21,6 +21,7 @@ public static class SqlMapper ...@@ -21,6 +21,7 @@ public static class SqlMapper
class CacheInfo class CacheInfo
{ {
public object Deserializer { get; set; } public object Deserializer { get; set; }
public object Deserializer2 { get; set; }
public Action<IDbCommand, object> ParamReader { get; set; } public Action<IDbCommand, object> ParamReader { get; set; }
} }
...@@ -90,19 +91,22 @@ private class Identity : IEquatable<Identity> ...@@ -90,19 +91,22 @@ private class Identity : IEquatable<Identity>
public String ConnectionString { get { return connectionString; } } public String ConnectionString { get { return connectionString; } }
public Type Type { get { return type; } } public Type Type { get { return type; } }
public Type Type2 { get { return Type2; } }
public string Sql { get { return sql; } } public string Sql { get { return sql; } }
public Type ParametersType { get { return ParametersType; } } public Type ParametersType { get { return ParametersType; } }
internal Identity(string sql, IDbConnection cnn, Type type, Type parametersType) internal Identity(string sql, IDbConnection cnn, Type type, Type parametersType, Type type2 = null)
{ {
this.sql = sql; this.sql = sql;
this.connectionString = cnn.ConnectionString; this.connectionString = cnn.ConnectionString;
this.type = type; this.type = type;
this.parametersType = parametersType; this.parametersType = parametersType;
this.type2 = type2;
unchecked unchecked
{ {
hashCode = 17; // we *know* we are using this in a dictionary, so pre-compute this hashCode = 17; // we *know* we are using this in a dictionary, so pre-compute this
hashCode = hashCode * 23 + (sql == null ? 0 : sql.GetHashCode()); hashCode = hashCode * 23 + (sql == null ? 0 : sql.GetHashCode());
hashCode = hashCode * 23 + (type == null ? 0 : type.GetHashCode()); hashCode = hashCode * 23 + (type == null ? 0 : type.GetHashCode());
hashCode = hashCode * 23 + (type2 == null ? 0 : type2.GetHashCode());
hashCode = hashCode * 23 + (connectionString == null ? 0 : connectionString.GetHashCode()); hashCode = hashCode * 23 + (connectionString == null ? 0 : connectionString.GetHashCode());
hashCode = hashCode * 23 + (parametersType == null ? 0 : parametersType.GetHashCode()); hashCode = hashCode * 23 + (parametersType == null ? 0 : parametersType.GetHashCode());
} }
...@@ -114,6 +118,7 @@ public override bool Equals(object obj) ...@@ -114,6 +118,7 @@ public override bool Equals(object obj)
private readonly string sql; private readonly string sql;
private readonly int hashCode; private readonly int hashCode;
private readonly Type type; private readonly Type type;
private readonly Type type2;
private readonly string connectionString; private readonly string connectionString;
private readonly Type parametersType; private readonly Type parametersType;
public override int GetHashCode() public override int GetHashCode()
...@@ -171,10 +176,8 @@ public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object ...@@ -171,10 +176,8 @@ public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object
private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null) private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null)
{ {
var identity = new Identity(sql, cnn, typeof(T), param == null ? null : param.GetType()); var identity = new Identity(sql, cnn, typeof(T), param == null ? null : param.GetType());
var info = GetCacheInfo(param, identity); var info = GetCacheInfo(param, identity);
using (var reader = GetReader(cnn, transaction, sql, info.ParamReader, param)) using (var reader = GetReader(cnn, transaction, sql, info.ParamReader, param))
{ {
if (info.Deserializer == null) if (info.Deserializer == null)
...@@ -190,7 +193,55 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq ...@@ -190,7 +193,55 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
yield return deserializer(reader); yield return deserializer(reader);
} }
} }
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="U"></typeparam>
/// <param name="cnn"></param>
/// <param name="sql"></param>
/// <param name="map"></param>
/// <param name="param"></param>
/// <param name="transaction"></param>
/// <param name="splitOn">The Field we should split and read the second object from (default: id)</param>
/// <returns></returns>
public static IEnumerable<T> Query<T, U>(this IDbConnection cnn, string sql, Action<T, U> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id")
{
var identity = new Identity(sql, cnn, typeof(T), param == null ? null : param.GetType());
var info = GetCacheInfo(param, identity);
using (var reader = GetReader(cnn, transaction, sql, info.ParamReader, param))
{
if (info.Deserializer == null)
{
int start = 0;
int length = -1;
for (length = 1; length < reader.FieldCount; length++)
{
if (reader.GetName(length) == splitOn)
{
break;
}
}
info.Deserializer = GetDeserializer<T>(identity, reader, start, length);
info.Deserializer2 = GetDeserializer<U>(identity, reader, start + length);
queryCache[identity] = info;
}
var deserializer = (Func<IDataReader, T>)info.Deserializer;
var deserializer2 = (Func<IDataReader, U>)info.Deserializer2;
while (reader.Read())
{
var tmp = deserializer(reader);
map(tmp, deserializer2(reader));
yield return tmp;
}
}
} }
private static CacheInfo GetCacheInfo(object param, Identity identity) private static CacheInfo GetCacheInfo(object param, Identity identity)
...@@ -207,18 +258,13 @@ private static CacheInfo GetCacheInfo(object param, Identity identity) ...@@ -207,18 +258,13 @@ private static CacheInfo GetCacheInfo(object param, Identity identity)
return info; return info;
} }
public static List<T> Query<T,U>(this IDbConnection cnn, string sql, Action<T,U> map, object param = null, IDbTransaction transaction = null)
{
return null;
}
static class DynamicStub static class DynamicStub
{ {
public static Type Type = typeof(DynamicStub); public static Type Type = typeof(DynamicStub);
} }
static Func<IDataReader, T> GetDeserializer<T>(Identity identity, IDataReader reader) static Func<IDataReader, T> GetDeserializer<T>(Identity identity, IDataReader reader, int startBound = 0, int length = -1)
{ {
object oDeserializer; object oDeserializer;
...@@ -228,7 +274,7 @@ static class DynamicStub ...@@ -228,7 +274,7 @@ static class DynamicStub
} }
else if (typeof(T).IsClass && typeof(T) != typeof(string)) else if (typeof(T).IsClass && typeof(T) != typeof(string))
{ {
oDeserializer = GetClassDeserializer<T>(reader); oDeserializer = GetClassDeserializer<T>(reader, startBound, length);
} }
else else
{ {
...@@ -475,7 +521,7 @@ private static object GetStructDeserializer<T>(IDataReader reader) ...@@ -475,7 +521,7 @@ private static object GetStructDeserializer<T>(IDataReader reader)
return deserializer; return deserializer;
} }
public static Func<IDataReader, T> GetClassDeserializer<T>(IDataReader reader) public static Func<IDataReader, T> GetClassDeserializer<T>(IDataReader reader, int startBound = 0, int length = -1)
{ {
DynamicMethod dm = new DynamicMethod("Deserialize" + Guid.NewGuid().ToString(), typeof(T), new Type[] { typeof(IDataReader) }, true); DynamicMethod dm = new DynamicMethod("Deserialize" + Guid.NewGuid().ToString(), typeof(T), new Type[] { typeof(IDataReader) }, true);
...@@ -487,8 +533,13 @@ private static object GetStructDeserializer<T>(IDataReader reader) ...@@ -487,8 +533,13 @@ private static object GetStructDeserializer<T>(IDataReader reader)
.Where(info => info.Setter != null) .Where(info => info.Setter != null)
.ToList(); .ToList();
if (length == -1)
{
length = reader.FieldCount - startBound;
}
var names = new List<string>(); var names = new List<string>();
for (int i = 0; i < reader.FieldCount; i++) for (int i = startBound; i < startBound + length; i++)
{ {
names.Add(reader.GetName(i)); names.Add(reader.GetName(i));
} }
...@@ -505,7 +556,7 @@ private static object GetStructDeserializer<T>(IDataReader reader) ...@@ -505,7 +556,7 @@ private static object GetStructDeserializer<T>(IDataReader reader)
.Where(p => p.GetIndexParameters().Any() && p.GetIndexParameters()[0].ParameterType == typeof(int)) .Where(p => p.GetIndexParameters().Any() && p.GetIndexParameters()[0].ParameterType == typeof(int))
.Select(p => p.GetGetMethod()).First(); .Select(p => p.GetGetMethod()).First();
int index = 0; int index = startBound;
// stack is empty // stack is empty
il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes)); // stack is now [target] il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes)); // stack is now [target]
......
...@@ -251,8 +251,23 @@ class Post ...@@ -251,8 +251,23 @@ class Post
} }
public void TestMultiMap() public void TestMultiMap()
{ {
var createSql = @"
create table #Users (Id int, Name varchar(20))
create table #Posts (Id int, OwnerId int, Content varchar(20))
var test = connection.Query<Post, User>("select * from Posts p left join Users u on u.Id = p.OwnerId", (post, user) => { post.Owner = user; }); insert #Users values(1, 'Sam')
insert #Users values(2, 'I am')
insert #Posts values(1, 1, 'Sams Post1')
insert #Posts values(2, 1, 'Sams Post2')
insert #Posts values(3, null, 'no ones post')
";
connection.Execute(createSql);
var data = connection.Query<Post, User>("select * from #Posts p left join #Users u on u.Id = p.OwnerId Order by p.Id", (post, user) => { post.Owner = user; });
data.First().Content.IsEqualTo("Sams Post1");
data.First().Owner.Name.IsEqualTo("Sam");
} }
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册