Я только что попробовал ваш пример в 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();