Un moyen de crĂ©er des filtres Linq rĂ©utilisables (gĂ©nĂ©rateurs de prĂ©dicat pour les clauses Where) qui peuvent ĂȘtre appliquĂ©s Ă diffĂ©rents types d'objets. Les champs des objets Ă filtrer sont spĂ©cifiĂ©s Ă l'aide de MemberExpression.
La méthode convient à Entity Framework, y compris les opérations Async.
Idée principale. Qu'est-ce qu'un filtre réutilisable?
Par exemple, il y a des commandes:
class Order {
public DateTime Start { get; set; }
public DateTime? End { get; set; }
}
Laissez-vous besoin de trouver toutes les commandes qui seront valables dans les 7 prochains jours.
En utilisant un générateur de filtre réutilisable (s'il a été implémenté), vous pouvez trouver des commandes comme celle-ci:
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.
Pour crĂ©er vos propres filtres rĂ©utilisables, vous n'avez besoin que de PredicateBuilder et MemberExpressionExtensions . Copiez-les simplement dans votre projet. Les filtres rĂ©utilisables peuvent ĂȘtre stylisĂ©s comme une extension (comme dans WhereOverlap), comme une aide statique ou comme une classe (comme dans UnderControlPayFilter).
J'ai créé quelques filtres réutilisables - GitHub , NuGet (comprend PredicateBuilder et MemberExpressionExtensions).