diff --git a/PetaPoco/PetaPoco.cs b/PetaPoco/PetaPoco.cs index 84e00048..ef9645f1 100644 --- a/PetaPoco/PetaPoco.cs +++ b/PetaPoco/PetaPoco.cs @@ -841,7 +841,7 @@ public IEnumerable Query(string sql, params object[] args) public IEnumerable Query(Sql sql) { return Query(new Type[] { typeof(T1), typeof(T2), typeof(T3), typeof(T4) }, null, sql.SQL, sql.Arguments); } // Automagically guess the property relationships between various POCOs and create a delegate that will set them up - object GetAutoMapper(Type[] types) + Delegate GetAutoMapper(Type[] types) { // Build a key var kb = new StringBuilder(); @@ -856,7 +856,7 @@ object GetAutoMapper(Type[] types) RWLock.EnterReadLock(); try { - object mapper; + Delegate mapper; if (AutoMappers.TryGetValue(key, out mapper)) return mapper; } @@ -870,7 +870,7 @@ object GetAutoMapper(Type[] types) try { // Try again - object mapper; + Delegate mapper; if (AutoMappers.TryGetValue(key, out mapper)) return mapper; @@ -946,19 +946,49 @@ Delegate FindSplitPoint(Type typeThis, Type typeNext, string sql, IDataReader r, // Instance data used by the Multipoco factory delegate - essentially a list of the nested poco factories to call class MultiPocoFactory { - public List m_Delegates; - public Delegate GetItem(int index) { return m_Delegates[index]; } + + public MultiPocoFactory(IEnumerable dels) + { + Delegates = new List(dels); + } + private List Delegates { get; set; } + private Delegate GetItem(int index) { return Delegates[index]; } + + /// + /// Calls the delegate at the specified index and returns its values + /// + /// + /// + /// + private object CallDelegate(int index, IDataReader reader) + { + var d = GetItem(index); + var output = d.DynamicInvoke(reader); + return output; + } + + /// + /// Calls the callback delegate and passes in the output of all delegates as the parameters + /// + /// + /// + /// + /// + /// + public TRet CallCallback(Delegate callback, IDataReader dr, int count) + { + var args = new List(); + for(var i = 0;i CreateMultiPocoFactory(Type[] types, string sql, IDataReader r) - { - var m = new DynamicMethod("petapoco_multipoco_factory", typeof(TRet), new Type[] { typeof(MultiPocoFactory), typeof(IDataReader), typeof(object) }, typeof(MultiPocoFactory)); - var il = m.GetILGenerator(); - - // Load the callback - il.Emit(OpCodes.Ldarg_2); - + Func CreateMultiPocoFactory(Type[] types, string sql, IDataReader r) + { // Call each delegate var dels = new List(); int pos = 0; @@ -967,33 +997,19 @@ Func CreateMultiPocoFactory(Type[] types, strin // Add to list of delegates to call var del = FindSplitPoint(types[i], i + 1 < types.Length ? types[i + 1] : null, sql, r, ref pos); dels.Add(del); - - // Get the delegate - il.Emit(OpCodes.Ldarg_0); // callback,this - il.Emit(OpCodes.Ldc_I4, i); // callback,this,Index - il.Emit(OpCodes.Callvirt, typeof(MultiPocoFactory).GetMethod("GetItem")); // callback,Delegate - il.Emit(OpCodes.Ldarg_1); // callback,delegate, datareader - - // Call Invoke - var tDelInvoke = del.GetType().GetMethod("Invoke"); - il.Emit(OpCodes.Callvirt, tDelInvoke); // Poco left on stack } - // By now we should have the callback and the N pocos all on the stack. Call the callback and we're done - il.Emit(OpCodes.Callvirt, Expression.GetFuncType(types.Concat(new Type[] { typeof(TRet) }).ToArray()).GetMethod("Invoke")); - il.Emit(OpCodes.Ret); - - // Finish up - return (Func)m.CreateDelegate(typeof(Func), new MultiPocoFactory() { m_Delegates = dels }); + var mpFactory = new MultiPocoFactory(dels); + return (reader, arg3) => mpFactory.CallCallback(arg3, reader, types.Length); } // Various cached stuff static Dictionary MultiPocoFactories = new Dictionary(); - static Dictionary AutoMappers = new Dictionary(); + static Dictionary AutoMappers = new Dictionary(); static System.Threading.ReaderWriterLockSlim RWLock = new System.Threading.ReaderWriterLockSlim(); - // Get (or create) the multi-poco factory for a query - Func GetMultiPocoFactory(Type[] types, string sql, IDataReader r) + // Get (or create) the multi-poco factory for a query + Func GetMultiPocoFactory(Type[] types, string sql, IDataReader r) { // Build a key string (this is crap, should address this at some point) var kb = new StringBuilder(); @@ -1015,7 +1031,10 @@ Func GetMultiPocoFactory(Type[] types, string s { object oFactory; if (MultiPocoFactories.TryGetValue(key, out oFactory)) - return (Func)oFactory; + { + //mpFactory = oFactory; + return (Func)oFactory; + } } finally { @@ -1029,13 +1048,15 @@ Func GetMultiPocoFactory(Type[] types, string s // Check again object oFactory; if (MultiPocoFactories.TryGetValue(key, out oFactory)) - return (Func)oFactory; - - // Create the factory - var Factory = CreateMultiPocoFactory(types, sql, r); + { + return (Func)oFactory; + } + + // Create the factory + var factory = CreateMultiPocoFactory(types, sql, r); - MultiPocoFactories.Add(key, Factory); - return Factory; + MultiPocoFactories.Add(key, factory); + return factory; } finally { @@ -1045,7 +1066,7 @@ Func GetMultiPocoFactory(Type[] types, string s } // Actual implementation of the multi-poco query - public IEnumerable Query(Type[] types, object cb, string sql, params object[] args) + public IEnumerable Query(Type[] types, Delegate cb, string sql, params object[] args) { OpenSharedConnection(); try