Я использую построитель предикатов EF Core для создания динамического оператора SQL. Однако мне очень трудно понять, как отрицать это выражение. Например, я использую оператор, чтобы выяснить, какие местоположения находятся внутри или за пределами географической границы.
Включение выглядит примерно так:
insidePredicate = insidePredicate.And(myBounds.IncludedExpression());
Код, генерирующий включенное выражение, представляет собой всего лишь метод расширения модели географических границ:
public static Expression<Func<MyLocation, bool>> IncludedExpression(this GeoBound geo)
{
return i => (geo.longitude <= i.Longitude && geo.latitude >= i.Latitude);
}
Хотя логика include
работает нормально, я хотел бы инвертировать эту логику и NOT
выделение, вот так:
outsidePredicate = outsidePredicate.Not(myBounds.IncludedExpression());
Это не работает, говоря: «Ни один метод перегрузки для NOT не принимает один параметр». Except
тоже не делает того, на что я надеюсь.
Как я могу инвертировать это выражение предиката с помощью построителя предикатов?
Предполагая, что вы используете PredicateBuilder
из LINQKit, если вы хотите отрицать какой-либо предикат, просто вызовите метод расширения Not, который имеет только один параметр (который будет outsidePredicate
в случае вызова outsidePredicate.Not
):
public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expr)
на выражении, которое вы хотите инвертировать, а затем объедините его с другим через And
или Or
. Например, если вы хотите отрицать myBounds.IncludedExpression()
, тогда вызов будет выглядеть так:
outsidePredicate = outsidePredicate.And(myBounds.IncludedExpression().Not());
Вы можете определить необязательный параметр для своего метода, чтобы обозначить его отрицание или его отсутствие, например
public static Expression<Func<MyLocation, bool>> IncludedExpression(this GeoBound geo, bool negated = false)
{
return i => ((geo.longitude <= i.Longitude && geo.latitude >= i.Latitude) != negated);
}
На самом деле это сделает ваш метод очень мощным, потому что, если вы не передадите логическое значение для negation
, он будет считать, что оно не было инвертировано, однако, если вы передадите ему логическое значение, оно будет обработано правильно.
Эта практика позволит вам не многократно выводить отрицание в коде, который его вызывает, а делегировать его внутренней логике, это сделает код очень читабельным, а также позволит избежать необходимости определять два метода для каждого предиката.
Таким образом, ваш код будет короче, компактнее и читабельнее.
Что такое
outsidePredicate
? Вы используете LINQKit?