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

implemented simple join multimap

上级 4ca04f91
......@@ -21,6 +21,7 @@ public static class SqlMapper
class CacheInfo
{
public object Deserializer { get; set; }
public object Deserializer2 { get; set; }
public Action<IDbCommand, object> ParamReader { get; set; }
}
......@@ -90,19 +91,22 @@ private class Identity : IEquatable<Identity>
public String ConnectionString { get { return connectionString; } }
public Type Type { get { return type; } }
public Type Type2 { get { return Type2; } }
public string Sql { get { return sql; } }
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.connectionString = cnn.ConnectionString;
this.type = type;
this.parametersType = parametersType;
this.type2 = type2;
unchecked
{
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 + (type == null ? 0 : type.GetHashCode());
hashCode = hashCode * 23 + (type2 == null ? 0 : type2.GetHashCode());
hashCode = hashCode * 23 + (connectionString == null ? 0 : connectionString.GetHashCode());
hashCode = hashCode * 23 + (parametersType == null ? 0 : parametersType.GetHashCode());
}
......@@ -114,6 +118,7 @@ public override bool Equals(object obj)
private readonly string sql;
private readonly int hashCode;
private readonly Type type;
private readonly Type type2;
private readonly string connectionString;
private readonly Type parametersType;
public override int GetHashCode()
......@@ -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)
{
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)
......@@ -190,7 +193,55 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
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)
......@@ -207,18 +258,13 @@ private static CacheInfo GetCacheInfo(object param, Identity identity)
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
{
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;
......@@ -228,7 +274,7 @@ static class DynamicStub
}
else if (typeof(T).IsClass && typeof(T) != typeof(string))
{
oDeserializer = GetClassDeserializer<T>(reader);
oDeserializer = GetClassDeserializer<T>(reader, startBound, length);
}
else
{
......@@ -475,7 +521,7 @@ private static object GetStructDeserializer<T>(IDataReader reader)
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);
......@@ -487,8 +533,13 @@ private static object GetStructDeserializer<T>(IDataReader reader)
.Where(info => info.Setter != null)
.ToList();
if (length == -1)
{
length = reader.FieldCount - startBound;
}
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));
}
......@@ -505,7 +556,7 @@ private static object GetStructDeserializer<T>(IDataReader reader)
.Where(p => p.GetIndexParameters().Any() && p.GetIndexParameters()[0].ParameterType == typeof(int))
.Select(p => p.GetGetMethod()).First();
int index = 0;
int index = startBound;
// stack is empty
il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes)); // stack is now [target]
......
......@@ -251,8 +251,23 @@ class Post
}
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.
先完成此消息的编辑!
想要评论请 注册