编辑:更详细的问题。
我正在研究nHibernate中的批处理操作,特别是In
查询,以克服SQL Server中的2100参数限制大小。
为此,我用这个构造函数创建了一个类(这是一个非常简化的版本):
BatchedQuery(session.Query<Foo>(), allValues, (l, e) => l.Contains(e.Id));
...
public BatchedQuery(IQueryable<TEntity> query, IList<TValue> allValues, Expression<Func<IList<TValue>, TEntity, bool>> predicate)
{
List<TValue> values = ...; // Select a batch from allValues
...
// I want to pass the values to the expression passed in...
// something like this, without using Compile:
// e => predicate.Compile()(values, e)
// using JKor's method, I tried this...
ParameterExpression param = Expression.Parameter(typeof(TEntity), "e");
Expression<Func<TEntity, bool>> expr2 =
Expression.Lambda<Func<TEntity, bool>>(Expression.Invoke(predicate,
Expression.Constant(batchOfValues), param), param);
query = query.Where(expr2);
// Do something with the query...
}
// Somewhere else..
// This causes the exception
batchedQuery.ToList();
以上是导致nHibernate抛出KeyNotFoundException
。
这是堆栈跟踪:
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at NHibernate.Param.NamedParameterSpecification.SetEffectiveType(QueryParameters queryParameters)
at NHibernate.Param.ParametersBackTrackExtensions.ResetEffectiveExpectedType(IEnumerable`1 parameterSpecs, QueryParameters queryParameters)
at NHibernate.Hql.Ast.ANTLR.Loader.QueryLoader.ResetEffectiveExpectedType(IEnumerable`1 parameterSpecs, QueryParameters queryParameters)
at NHibernate.Loader.Loader.CreateSqlCommand(QueryParameters queryParameters, ISessionImplementor session)
at NHibernate.Impl.MultiQueryImpl.AggregateQueriesInformation()
at NHibernate.Impl.MultiQueryImpl.get_Parameters()
at NHibernate.Impl.MultiQueryImpl.CreateCombinedQueryParameters()
at NHibernate.Impl.MultiQueryImpl.List()
at NHibernate.Impl.FutureQueryBatch.GetResultsFrom(IMultiQuery multiApproach)
at NHibernate.Impl.FutureBatch`2.GetResults()
at NHibernate.Impl.FutureBatch`2.get_Results()
at NHibernate.Impl.FutureBatch`2.GetCurrentResult[TResult](Int32 currentIndex)
at NHibernate.Impl.FutureBatch`2.<>c__DisplayClass4`1.<GetEnumerator>b__3()
at NHibernate.Impl.DelayedEnumerator`1.<get_Enumerable>d__0.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at NovusERP.Data.Helpers.BatchedQuery`2.ToList() in D:\Short Utilities\Novus\NovusERP\NovusERP.Data\Helpers\BatchedQuery.cs:line 63
at NovusERP.Modules.Payroll.Attendance.AttendanceViewModel.GetEmployees(IList`1 selectedEmployeeIds) in D:\Short Utilities\Novus\NovusERP\NovusERP.Modules\Payroll\Attendance\AttendanceViewModel.cs:line 79
at NovusERP.Modules.Payroll.Attendance.AttendanceViewModel..ctor(MonthYear currentMonth, IList`1 selectedEmployeeIds) in D:\Short Utilities\Novus\NovusERP\NovusERP.Modules\Payroll\Attendance\AttendanceViewModel.cs:line 47
at NovusERP.Modules.Payroll.Attendance.AttendanceView..ctor(MonthYear currentMonth, IList`1 selectedEmployees) in D:\Short Utilities\Novus\NovusERP\NovusERP.Modules\Payroll\Attendance\AttendanceView.xaml.cs:line 18
at lambda_method(Closure , Object[] )
at Autofac.Core.Activators.Reflection.ConstructorParameterBinding.Instantiate()
有人能指出我正确的方向吗?任何帮助将受到高度赞赏。
问候,
约杰什。
答案 0 :(得分:1)
如果你想在没有编译expr1的情况下创建expr2,你不能只使用内置的编译器转换。这就是你想要的:
Expression<Func<IList<TValue>, TEntity, bool>> expr1 = (l, e) => l.Contains(e.Id);
ParameterExpression param = Expression.Parameter(typeof(TEntity), "e");
Expresssion<Func<TEntity, bool>> expr2 = Expression.Lambda<Func<TEntity, bool>>(Expression.Invoke(expr1, Expression.Constant(values), param), param);
答案 1 :(得分:0)
我发布了我的回答,以便其他人可以从中受益。
做我想做的最好的方法是使用ExpressionVisitor
和Expression.Lambda
并使用适当的更改制作整个表达式的副本。此类是3 / 3.5中的内部类,因此如果要将此类用于3 / 3.5,here是该类的完整实现。网上有很多可用的教程。
其次,任何想要获得解析和可视化表达式树的工具的人都应该在VS 2008中获得ExpressionTreeVisualizer
样本。您必须将样本转换并编译为VS 2010 for .Net 4.0。 Patrick Smacchia的This blog post可以帮助您。
对于上述所有内容的一个注意事项,即使在我在本回答中解释的方式转换查询后,nhibernate仍会抛出异常。只有当我尝试将查询转换为将来的查询然后对其进行评估时,才会发生这种情况。如果不将查询转换为将来,它可以正常工作。我正在寻找相同的解决方案。如果我发现它为什么会发生以及解决方案是什么,我会相应地更新答案。