Почему я получаю это исключение Linq to Nhibernate, когда я дважды добавляю одно и то же выражение в запрос?

#linq #linq-to-nhibernate #predicatebuilder

#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:CSharpNHNHnhibernatesrcNHibernateLinqVisitorsExpressionParameterVisitor.cs:line 43
   at Remotion.Linq.Parsing.ExpressionTreeVisitor.VisitExpression(Expression expression) in :line 0
   at NHibernate.Linq.Visitors.NhExpressionTreeVisitor.VisitExpression(Expression expression) in d:CSharpNHNHnhibernatesrcNHibernateLinqVisitorsNhExpressionTreeVisitor.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:CSharpNHNHnhibernatesrcNHibernateLinqVisitorsNhExpressionTreeVisitor.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:CSharpNHNHnhibernatesrcNHibernateLinqVisitorsNhExpressionTreeVisitor.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:CSharpNHNHnhibernatesrcNHibernateLinqVisitorsNhExpressionTreeVisitor.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:CSharpNHNHnhibernatesrcNHibernateLinqVisitorsNhExpressionTreeVisitor.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:CSharpNHNHnhibernatesrcNHibernateLinqVisitorsNhExpressionTreeVisitor.cs:line 32
   at NHibernate.Linq.Visitors.ExpressionParameterVisitor.Visit(Expression expression) in d:CSharpNHNHnhibernatesrcNHibernateLinqVisitorsExpressionParameterVisitor.cs:line 21
   at NHibernate.Linq.NhLinqExpression..ctor(Expression expression) in d:CSharpNHNHnhibernatesrcNHibernateLinqNhLinqExpression.cs:line 38
   at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQueryamp; query, NhLinqExpressionamp; nhQuery) in d:CSharpNHNHnhibernatesrcNHibernateLinqDefaultQueryProvider.cs:line 67
   at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression) in d:CSharpNHNHnhibernatesrcNHibernateLinqDefaultQueryProvider.cs:line 33
   at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression) in d:CSharpNHNHnhibernatesrcNHibernateLinqDefaultQueryProvider.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:UsersIsaac.GDesktopcheckoutField SystemFieldSystemFieldSystemCoreReportsObservationReportObservationReportSearch.cs:line 39
   at FieldSystemGUI.Controls.Reports.ObservationReport.ObservationReport_ReportSearchEvent(Object sender, DoWorkEventArgs e) in C:UsersIsaac.GDesktopcheckoutField SystemFieldSystemFieldSystemGUIControlsReportsObservationReport.cs:line 99
   at GUIComponents.Controls.Reports.BaseCommonReport.backgroundWorker_DoWork(Object sender, DoWorkEventArgs e) in C:UsersIsaac.GDesktopcheckoutLibrary ProjectsGUIComponentsGUIComponentsControlsReportsBaseCommonReport.cs:line 194
   at System.ComponentModel.BackgroundWorker.OnDoWork(DoWorkEventArgs e)
   at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)
 

Комментарии:

1. Какое исключение вы получаете?

2. «Элемент с тем же ключом уже добавлен». Система. Я считаю, что ArgumentsException

Ответ №1:

Я только что попробовал ваш пример в LINQ to Objects, LINQ to SQL и LINQ to Entities, и он отлично работает во всех из них (с небольшими изменениями). Возможно, вы захотите сообщить об этом как об ошибке команде LINQ to NHibernate.

Чтобы «скопировать» дерево выражений, вам нужно будет скопировать каждый узел этого дерева, используя что-то вроде an 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(); 
 

Комментарии:

1. Я попробую это. Спасибо. Я потратил часы, пытаясь выяснить, что я делаю неправильно.

2. Обходной путь сработал. Я бы не подумал сделать это без вас! Я предполагаю, что метод копирования, который я использую, не является «истинной» копией.

3. В вашем обновлении: трюк с изменением не сработал. Большое спасибо за все время, которое вы тратите на эту раздражающую проблему

Ответ №2:

Комментарии:

1. Я только что попробовал это на самом деле. Это не работает. Я все еще получаю исключение. Это очень неприятно, потому что я не знаю, что такое дублирующий ключ. Кажется, это происходит, когда я пытаюсь дважды добавить одну и ту же переменную предиката.