当我向查询添加两次相同的表达式时,为什么我将此Linq变为Nhibernate异常?

时间:2011-10-21 00:35:07

标签: linq linq-to-nhibernate predicatebuilder

我有问题。我收到了“已添加相同密钥的项目”。我尝试枚举查询结果时出现异常。当我尝试在最终查询中包含来自相同原始变量的表达式时,会发生这种情况。我试图通过复制表达来解决这个问题,但无济于事:

var predicate1 = PredicateBuilder.True<SomeType>();
var predicate2 = PredicateBuilder.True<SomeType>();
var predicate3 = PredicateBuilder.True<SomeType>();   


    System.Linq.Expressions.Expression<Func<FieldObservation, bool>> predicate1copy1 =           System.Linq.Expressions.Expression.Lambda<Func<FieldObservation, bool>>(predicate1.Body, predicate1.Parameters);
    System.Linq.Expressions.Expression<Func<FieldObservation, bool>> predicate1copy2 = System.Linq.Expressions.Expression.Lambda<Func<FieldObservation, bool>>(predicate1.Body, predicate1.Parameters);

    predicate2 = x => x.FirstBoolProperty;
    predicate2 = predicate2.And(predicate1copy1); 
    predicate3 = x => x.SecondBoolProperty;
    predicate3 = predicate3.And(predicate1copy2); //predicate1copy2 comes from the same original predicate1
    var predicate4 = predicate2.Or(predicate3);
    var results1 = query.Where(predicate4).ToList(); //exception thrown here: "An item with the same key has already been added."

我正在使用Linq来Nhibernate。这是堆栈跟踪。谁能解释一下呢?

Stacktrace:
   at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
   at NHibernate.Linq.Visitors.ExpressionParameterVisitor.VisitConstantExpression(ConstantExpression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\ExpressionParameterVisitor.cs:line 43
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
   at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitBinaryExpression(BinaryExpression expression) in :line 0
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
   at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitBinaryExpression(BinaryExpression expression) in :line 0
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
   at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitLambdaExpression(LambdaExpression expression) in :line 0
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
   at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitUnaryExpression(UnaryExpression expression) in :line 0
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
   at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitAndConvert[T](T expression, String methodName) in :line 0
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.<>c__DisplayClass6`1.<VisitAndConvert>b__5(T expression) in :line 0
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitList[T](ReadOnlyCollection`1 list, Func`2 visitMethod) in :line 0
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitAndConvert[T](ReadOnlyCollection`1 expressions, String callerName) in :line 0
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitMethodCallExpression(MethodCallExpression expression) in :line 0
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
   at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\NhExpressionTreeVisitor.cs:line 32
   at NHibernate.Linq.Visitors.ExpressionParameterVisitor.Visit(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\Visitors\ExpressionParameterVisitor.cs:line 21
   at NHibernate.Linq.NhLinqExpression..ctor(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\NhLinqExpression.cs:line 38
   at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\DefaultQueryProvider.cs:line 67
   at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\DefaultQueryProvider.cs:line 33
   at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Linq\DefaultQueryProvider.cs:line 40
   at Remotion.Linq.QueryableBase`1.GetEnumerator() in :line 0
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at FieldSystemCore.Reports.ObservationReport.ObservationReportSearch.getResults(ObservationReportConfigurationObject config) in C:\Users\Isaac.G\Desktop\checkout\Field System\FieldSystem\FieldSystemCore\Reports\ObservationReport\ObservationReportSearch.cs:line 39
   at FieldSystemGUI.Controls.Reports.ObservationReport.ObservationReport_ReportSearchEvent(Object sender, DoWorkEventArgs e) in C:\Users\Isaac.G\Desktop\checkout\Field System\FieldSystem\FieldSystemGUI\Controls\Reports\ObservationReport.cs:line 99
   at GUIComponents.Controls.Reports.BaseCommonReport.backgroundWorker_DoWork(Object sender, DoWorkEventArgs e) in C:\Users\Isaac.G\Desktop\checkout\Library Projects\GUIComponents\GUIComponents\Controls\Reports\BaseCommonReport.cs:line 194
   at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
   at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)

2 个答案:

答案 0 :(得分:1)

这是一个长期猜测。

您可以将其添加到predicatebuilder

的副本中
public static Expression<Func<T, bool>> Copy<T>
  (this Expression<Func<T, bool>> expr1)
{
  return Expression.Lambda<Func<T, bool>>(expr1.Body, expr1.Parameters);
}

然后使用它:

predicate3 = predicate3.And(predicate1.Copy());

可能无法解决您的重复密钥问题 - 我没有看到任何字典涉及。你在猜什么?

答案 1 :(得分:1)

我刚尝试了LINQ to Objects,LINQ to SQL和LINQ to Entities中的示例,并且它在所有这些中都运行良好(只需稍加调整)。您可能希望将其作为错误报告给LINQ to NHibernate团队。

为了“复制”表达式树,你必须使用类似ExpressionVisitor之类的东西来复制该树的每个节点,这很麻烦,可能会或可能不会最终修复你的问题。

根据代码的结构,一种解决方法可能是重复原始表达式树两次,通过传入第一个产生该表达式的内容:

Func<Expression<Func<SomeType, bool>>> predicate1Builder = 
    () => PredicateBuilder.True<SomeType>();

var predicate2 = PredicateBuilder.True<SomeType>();
var predicate3 = PredicateBuilder.True<SomeType>();    

predicate2 = x => x.FirstBoolProperty;
predicate2 = predicate2.And(predicate1Builder());
predicate3 = x => x.SecondBoolProperty;
predicate3 = predicate3.And(predicate1Builder()); 
var predicate4 = predicate2.Or(predicate3);
var results1 = query.Where(predicate4).ToList(); 

更新

我只花了一些时间阅读ExpressionVisitors,看起来它可能并不那么困难。看看是否有效:

public class Visitor : ExpressionVisitor
{
    public Expression<T> Modify<T>(Expression<T> node) {return (Expression<T>)Visit(node);}
}

var predicate1 = PredicateBuilder.True<SomeType>();
var predicate2 = PredicateBuilder.True<SomeType>();
var predicate3 = PredicateBuilder.True<SomeType>();    

predicate2 = x => x.FirstBoolProperty;
predicate2 = predicate2.And(predicate1);
predicate3 = x => x.SecondBoolProperty;
var copy = new Visitor().Modify(predicate1);
predicate3 = predicate3.And(copy); 
var predicate4 = predicate2.Or(predicate3);

var results1 = query.Where(predicate4).ToList();