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

dynamic multi deserialization for extra awesome

bug fix around null objects
上级 ab15443e
......@@ -227,8 +227,25 @@ private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sq
}
}
info.Deserializer = GetDeserializer<T>(identity, reader, start, length);
info.Deserializer2 = GetDeserializer<U>(identity, reader, start + length);
// dynamic comes back as object ...
if (typeof(T) == typeof(object))
{
info.Deserializer = GetDeserializer<ExpandoObject>(identity, reader, start, length);
}
else
{
info.Deserializer = GetDeserializer<T>(identity, reader, start, length);
}
if (typeof(U) == typeof(object))
{
info.Deserializer2 = GetDeserializer<ExpandoObject>(identity, reader, start + length,returnNullIfFirstMissing:true);
}
else
{
info.Deserializer2 = GetDeserializer<U>(identity, reader, start + length, returnNullIfFirstMissing: true);
}
queryCache[identity] = info;
}
......@@ -259,22 +276,22 @@ private static CacheInfo GetCacheInfo(object param, Identity identity)
}
static class DynamicStub
class DynamicStub
{
public static Type Type = typeof(DynamicStub);
}
static Func<IDataReader, T> GetDeserializer<T>(Identity identity, IDataReader reader, int startBound = 0, int length = -1)
static Func<IDataReader, T> GetDeserializer<T>(Identity identity, IDataReader reader, int startBound = 0, int length = -1, bool returnNullIfFirstMissing = false)
{
object oDeserializer;
if (typeof(T) == DynamicStub.Type || typeof(T) == typeof(ExpandoObject))
{
oDeserializer = GetDynamicDeserializer(reader);
oDeserializer = GetDynamicDeserializer(reader,startBound, length, returnNullIfFirstMissing);
}
else if (typeof(T).IsClass && typeof(T) != typeof(string))
{
oDeserializer = GetClassDeserializer<T>(reader, startBound, length);
oDeserializer = GetClassDeserializer<T>(reader, startBound, length, returnNullIfFirstMissing: returnNullIfFirstMissing);
}
else
{
......@@ -285,10 +302,16 @@ static class DynamicStub
return deserializer;
}
private static object GetDynamicDeserializer(IDataReader reader)
private static object GetDynamicDeserializer(IDataReader reader, int startBound = 0, int length = -1, bool returnNullIfFirstMissing = false)
{
List<string> colNames = new List<string>();
for (int i = 0; i < reader.FieldCount; i++)
if (length == -1)
{
length = reader.FieldCount - startBound;
}
for (int i = startBound; i < startBound + length; i++)
{
colNames.Add(reader.GetName(i));
}
......@@ -297,12 +320,19 @@ private static object GetDynamicDeserializer(IDataReader reader)
r =>
{
IDictionary<string, object> row = new ExpandoObject();
int i = 0;
int i = startBound;
bool first = true;
foreach (var colName in colNames)
{
var tmp = r.GetValue(i);
row[colName] = tmp == DBNull.Value ? null : tmp;
tmp = tmp == DBNull.Value ? null : tmp;
row[colName] = tmp;
if (returnNullIfFirstMissing && first && tmp == null)
{
return null;
}
i++;
first = false;
}
return (ExpandoObject)row;
};
......@@ -521,7 +551,7 @@ private static object GetStructDeserializer<T>(IDataReader reader)
return deserializer;
}
public static Func<IDataReader, T> GetClassDeserializer<T>(IDataReader reader, int startBound = 0, int length = -1)
public static Func<IDataReader, T> GetClassDeserializer<T>(IDataReader reader, int startBound = 0, int length = -1, bool returnNullIfFirstMissing = false)
{
DynamicMethod dm = new DynamicMethod("Deserialize" + Guid.NewGuid().ToString(), typeof(T), new Type[] { typeof(IDataReader) }, true);
......@@ -560,6 +590,7 @@ private static object GetStructDeserializer<T>(IDataReader reader)
// stack is empty
il.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes)); // stack is now [target]
bool first = true;
foreach (var item in setters)
{
if (item.Info != null)
......@@ -581,13 +612,21 @@ private static object GetStructDeserializer<T>(IDataReader reader)
il.Emit(OpCodes.Callvirt, item.Info.Setter); // stack is now [target]
il.Emit(OpCodes.Br_S, finishLabel); // stack is now [target]
il.MarkLabel(isDbNullLabel); // incoming stack: [target][target][value]
il.Emit(OpCodes.Pop); // stack is now [target][target]
il.Emit(OpCodes.Pop); // stack is now [target]
if (first && returnNullIfFirstMissing)
{
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ldnull); // stack is now [null]
il.Emit(OpCodes.Ret);
}
il.MarkLabel(finishLabel);
}
first = false;
index += 1;
}
il.Emit(OpCodes.Ret); // stack is empty
......
......@@ -269,13 +269,53 @@ public void TestMultiMap()
left join #Users u on u.Id = p.OwnerId
Order by p.Id";
var data = connection.Query<Post, User>(sql, (post, user) => { post.Owner = user; });
var data = connection.Query<Post, User>(sql, (post, user) => { post.Owner = user; }).ToList();
var p = data.First();
p.Content.IsEqualTo("Sams Post1");
p.Id.IsEqualTo(1);
p.Owner.Name.IsEqualTo("Sam");
p.Owner.Id.IsEqualTo(99);
data[2].Owner.IsNull();
connection.Execute("drop table #Users drop table #Posts");
}
public void TestMultiMapDynamic()
{
var createSql = @"
create table #Users (Id int, Name varchar(20))
create table #Posts (Id int, OwnerId int, Content varchar(20))
insert #Users values(99, 'Sam')
insert #Users values(2, 'I am')
insert #Posts values(1, 99, 'Sams Post1')
insert #Posts values(2, 99, 'Sams Post2')
insert #Posts values(3, null, 'no ones post')
";
connection.Execute(createSql);
var sql =
@"select * from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id";
var data = connection.Query<dynamic, dynamic>(sql, (post, user) => { post.Owner = user; }).ToList();
var p = data.First();
// hairy extension method support for dynamics
((string)p.Content).IsEqualTo("Sams Post1");
((int)p.Id).IsEqualTo(1);
((string)p.Owner.Name).IsEqualTo("Sam");
((int)p.Owner.Id).IsEqualTo(99);
((object)data[2].Owner).IsNull();
connection.Execute("drop table #Users drop table #Posts");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册