Eine Möglichkeit, wiederverwendbare Linq-Filter (Prädikat-Builder für Where-Klauseln) zu erstellen, die auf verschiedene Objekttypen angewendet werden können. Die Felder der zu filternden Objekte werden mit MemberExpression angegeben.
Die Methode eignet sich für Entity Framework, einschließlich Async-Vorgängen.
Hauptidee. Was ist ein wiederverwendbarer Filter?
Zum Beispiel gibt es Befehle:
class Order {
public DateTime Start { get; set; }
public DateTime? End { get; set; }
}
Sie müssen alle Bestellungen finden, die in den nächsten 7 Tagen gültig sein werden.
Mit einem wiederverwendbaren Filter-Builder (falls implementiert) können Sie Aufträge wie folgt finden:
var ordersFiltred = orders
.WhereOverlap(
// MemberExpressions
//
fromField: oo => oo.Start,
toField: oo => oo.End,
//
from: DateTime.Now,
to: DateTime.Now.AddDays(7))
.ToList();
WhereOverlap . , :
class Trip {
public DateTime? From { get; set; }
public DateTime? To { get; set; }
}
var tripsFiltred = trips
.WhereOverlap(
// MemberExpressions
//
fromField: oo => oo.From,
toField: oo => oo.To,
from: DateTime.Now,
to: DateTime.Now.AddDays(7))
.ToList();
- , , -. ( ) WhereOverlap.
.
WhereOverlap, . , WhereOverlap, “”, “”. .
:
class Payout {
public decimal Total { get; set; }
public bool UnderControl { get; set; }
}
class Premium {
public decimal Sum { get; set; }
public bool RequiresConfirmation { get; set; }
}
:
class UnderControlPayFilter {
readonly decimal Limit;
public UnderControlPayFilter(decimal limit) {
Limit = limit;
}
public Expression<Func<TEnt, bool>> Create<TEnt>(
Expression<Func<TEnt, decimal>> sumField) {
// GreaterOrEqual -
// GreaterOrEqual - extension,
// - (Expression sumField)
// - (Limit)
return sumField.GreaterOrEqual(Limit);
}
}
UnderControlPayFilter :
//
//
// ( 1000) ,
// UnderControlPayFilter IoC-.
// ( )
//
var underControlPayFilter = new UnderControlPayFilter(1000);
//
//
var payoutPredicate =
underControlPayFilter.Create<Payout>(pp => pp.Total);
// , , payouts - ,
// Entity Framework DbSet
var payouts = new[] {
new Payout{ Total = 100 },
new Payout{ Total = 50, UnderControl = true },
new Payout{ Total = 25.5m },
new Payout{ Total = 1050.67m }
}
.AsQueryable()
.Where(payoutPredicate)
.ToList();
//
//
var premiumPredicate =
underControlPayFilter.Create<Premium>(pp => pp.Sum);
// , , premiums - ,
// Entity Framework DbSet
var premiums = new[] {
new Premium{ Sum = 2000 },
new Premium{ Sum = 50.08m },
new Premium{ Sum = 25.5m, RequiresConfirmation = true },
new Premium{ Sum = 1070.07m }
}
.AsQueryable()
.Where(premiumPredicate)
.ToList();
, GreaterOrEqual extension:
public static class MemberExpressionExtensions {
public static Expression<Func<TEnt, bool>> GreaterOrEqual<TEnt, TProp>(
this Expression<Func<TEnt, TProp>> field, TProp val)
=> Expression.Lambda<Func<TEnt, bool>>(
Expression.GreaterThanOrEqual(field.Body, Expression.Constant(val, typeof(TProp))),
field.Parameters);
}
extension- LessOrEqual, Equal, HasNoVal .
“” “”
, , , .
UnderControlPayFilter:
class UnderControlPayFilter {
readonly decimal Limit;
public UnderControlPayFilter(decimal limit) {
Limit = limit;
}
public Expression<Func<TEnt, bool>> Create<TEnt>(
Expression<Func<TEnt, decimal>> sumField,
Expression<Func<TEnt, bool>> controlMarkField) {
// PredicateBuilder (. )
return PredicateBuilder.Or(
sumField.GreaterOrEqual(Limit),
controlMarkField.Equal(true));
}
}
:
//
var payoutPredicate =
underControlPayFilter.Create<Payout>(
sumField: pp => pp.Total,
controlMarkField: pp => pp.UnderControl);
//
var premiumPredicate =
underControlPayFilter.Create<Premium>(
sumField: pp => pp.Sum,
controlMarkField: pp => pp.RequiresConfirmation);
PredicateBuilder “A universal PredicateBuilder” Pete Montgomery.
Um Ihre eigenen wiederverwendbaren Filter zu erstellen, benötigen Sie nur PredicateBuilder und MemberExpressionExtensions . Kopieren Sie sie einfach in Ihr Projekt. Wiederverwendbare Filter können als Erweiterung (wie in WhereOverlap), als statischer Helfer oder als Klasse (wie in UnderControlPayFilter) gestaltet werden.
Ich habe einige wiederverwendbare Filter erstellt - GitHub , NuGet (einschließlich PredicateBuilder und MemberExpressionExtensions).