diff --git a/src/Umbraco.Core/Persistence/PetaPoco.cs b/src/Umbraco.Core/Persistence/PetaPoco.cs index d8507ac681..56e9fecdb9 100644 --- a/src/Umbraco.Core/Persistence/PetaPoco.cs +++ b/src/Umbraco.Core/Persistence/PetaPoco.cs @@ -842,7 +842,7 @@ namespace Umbraco.Core.Persistence 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 - Delegate GetAutoMapper(Type[] types) + object GetAutoMapper(Type[] types) { // Build a key var kb = new StringBuilder(); @@ -857,7 +857,7 @@ namespace Umbraco.Core.Persistence RWLock.EnterReadLock(); try { - Delegate mapper; + object mapper; if (AutoMappers.TryGetValue(key, out mapper)) return mapper; } @@ -871,7 +871,7 @@ namespace Umbraco.Core.Persistence try { // Try again - Delegate mapper; + object mapper; if (AutoMappers.TryGetValue(key, out mapper)) return mapper; @@ -944,53 +944,22 @@ namespace Umbraco.Core.Persistence throw new InvalidOperationException(string.Format("Couldn't find split point between {0} and {1}", typeThis, typeNext)); } - // Instance data used by the Multipoco factory delegate - essentially a list of the nested poco factories to call public class MultiPocoFactory { - - 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 m_Delegates; + public Delegate GetItem(int index) { return m_Delegates[index]; } } // Create a multi-poco factory - Func CreateMultiPocoFactory(Type[] types, string sql, IDataReader r) - { + Func 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); + // Call each delegate var dels = new List(); int pos = 0; @@ -999,19 +968,33 @@ namespace Umbraco.Core.Persistence // 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 } - var mpFactory = new MultiPocoFactory(dels); - return (reader, arg3) => mpFactory.CallCallback(arg3, reader, types.Length); + // 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 }); } // 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(); @@ -1033,10 +1016,7 @@ namespace Umbraco.Core.Persistence { object oFactory; if (MultiPocoFactories.TryGetValue(key, out oFactory)) - { - //mpFactory = oFactory; - return (Func)oFactory; - } + return (Func)oFactory; } finally { @@ -1048,17 +1028,15 @@ namespace Umbraco.Core.Persistence try { // Check again - object oFactory; ; + object oFactory; if (MultiPocoFactories.TryGetValue(key, out oFactory)) - { - return (Func)oFactory; - } - - // Create the factory - var factory = CreateMultiPocoFactory(types, sql, r); + return (Func)oFactory; - MultiPocoFactories.Add(key, factory); - return factory; + // Create the factory + var Factory = CreateMultiPocoFactory(types, sql, r); + + MultiPocoFactories.Add(key, Factory); + return Factory; } finally { @@ -1068,7 +1046,7 @@ namespace Umbraco.Core.Persistence } // Actual implementation of the multi-poco query - public IEnumerable Query(Type[] types, Delegate cb, string sql, params object[] args) + public IEnumerable Query(Type[] types, object cb, string sql, params object[] args) { OpenSharedConnection(); try