diff --git a/src/NHibernate/Async/Multi/LinqBatchItem.cs b/src/NHibernate/Async/Multi/LinqBatchItem.cs index 638948f3cf5..d27fface8e3 100644 --- a/src/NHibernate/Async/Multi/LinqBatchItem.cs +++ b/src/NHibernate/Async/Multi/LinqBatchItem.cs @@ -14,7 +14,6 @@ using System.Linq; using System.Linq.Expressions; using NHibernate.Linq; -using NHibernate.Util; using Remotion.Linq.Parsing.ExpressionVisitors; namespace NHibernate.Multi @@ -22,7 +21,7 @@ namespace NHibernate.Multi using System.Threading.Tasks; using System.Threading; - public partial class LinqBatchItem : QueryBatchItem + public partial class LinqBatchItem : QueryBatchItem, ILinqBatchItem { protected override async Task> GetResultsNonBatchedAsync(CancellationToken cancellationToken) diff --git a/src/NHibernate/Multi/LinqBatchItem.cs b/src/NHibernate/Multi/LinqBatchItem.cs index fdbf9f1be2f..733b3115505 100644 --- a/src/NHibernate/Multi/LinqBatchItem.cs +++ b/src/NHibernate/Multi/LinqBatchItem.cs @@ -4,11 +4,15 @@ using System.Linq; using System.Linq.Expressions; using NHibernate.Linq; -using NHibernate.Util; using Remotion.Linq.Parsing.ExpressionVisitors; namespace NHibernate.Multi { + interface ILinqBatchItem + { + List GetTypedResults(); + } + public static class LinqBatchItem { public static LinqBatchItem Create(IQueryable query, Expression, TResult>> selector) @@ -42,9 +46,10 @@ private static LinqBatchItem GetForQuery(IQueryable query, Exp /// Create instance via methods /// /// Result type - public partial class LinqBatchItem : QueryBatchItem + public partial class LinqBatchItem : QueryBatchItem, ILinqBatchItem { private readonly Delegate _postExecuteTransformer; + private readonly System.Type _resultTypeOverride; public LinqBatchItem(IQuery query) : base(query) { @@ -53,6 +58,7 @@ public LinqBatchItem(IQuery query) : base(query) internal LinqBatchItem(IQuery query, NhLinqExpression linq) : base(query) { _postExecuteTransformer = linq.ExpressionToHqlTranslationResults.PostExecuteTransformer; + _resultTypeOverride = linq.ExpressionToHqlTranslationResults.ExecuteResultTypeOverride; } protected override IList GetResultsNonBatched() @@ -69,11 +75,10 @@ protected override List DoGetResults() { if (_postExecuteTransformer != null) { - var elementType = GetResultTypeIfChanged(); - - IList transformerList = elementType == null + IList transformerList = _resultTypeOverride == null ? base.DoGetResults() - : GetTypedResults(elementType); + //see LinqToFutureValueFixture tests that cover this scenario + : LinqBatchReflectHelper.GetTypedResults(this, _resultTypeOverride); return GetTransformedResults(transformerList); } @@ -90,27 +95,9 @@ private List GetTransformedResults(IList transformerList) }; } - private System.Type GetResultTypeIfChanged() - { - if (_postExecuteTransformer == null) - { - return null; - } - var elementType = _postExecuteTransformer.Method.GetParameters()[1].ParameterType.GetGenericArguments()[0]; - if (typeof(T).IsAssignableFrom(elementType)) - { - return null; - } - - return elementType; - } - - private IList GetTypedResults(System.Type type) + List ILinqBatchItem.GetTypedResults() { - var method = ReflectHelper.GetMethod(() => GetTypedResults()) - .GetGenericMethodDefinition(); - var generic = method.MakeGenericMethod(type); - return (IList) generic.Invoke(this, null); + return GetTypedResults(); } } } diff --git a/src/NHibernate/Multi/LinqBatchReflectHelper.cs b/src/NHibernate/Multi/LinqBatchReflectHelper.cs new file mode 100644 index 00000000000..4d1037a4e75 --- /dev/null +++ b/src/NHibernate/Multi/LinqBatchReflectHelper.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Linq.Expressions; +using System.Reflection; +using NHibernate.Util; + +namespace NHibernate.Multi +{ + static class LinqBatchReflectHelper + { + private static readonly ConcurrentDictionary> GetResultsForTypeDic = new ConcurrentDictionary>(); + + private static readonly MethodInfo GetTypedResultsMethod = ReflectHelper.GetMethod((ILinqBatchItem i) => i.GetTypedResults()).GetGenericMethodDefinition(); + + internal static IList GetTypedResults(ILinqBatchItem batchItem, System.Type type) + { + return GetResultsForTypeDic.GetOrAdd(type, t => CompileDelegate(t)).Invoke(batchItem); + } + + private static Func CompileDelegate(System.Type type) + { + var generic = GetTypedResultsMethod.MakeGenericMethod(type); + var instance = Expression.Parameter(typeof(ILinqBatchItem)); + var methodCall = Expression.Call(instance, generic); + return Expression.Lambda>(methodCall, instance).Compile(); + } + } +}