Uma maneira de criar filtros Linq reutilizáveis (construtores de predicado para cláusulas Where) que podem ser aplicados a diferentes tipos de objetos. Os campos de objetos a serem filtrados são especificados usando MemberExpression.
O método é adequado para Entity Framework, incluindo operações Async.
Ideia principal. O que é um filtro reutilizável?
Por exemplo, existem pedidos:
class Order {
public DateTime Start { get; set; }
public DateTime? End { get; set; }
}
Deixe que você encontre todos os pedidos que serão válidos nos próximos 7 dias.
Usando um criador de filtro reutilizável (se foi implementado), você pode encontrar pedidos como este:
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.
Para fazer seus próprios filtros reutilizáveis, você só precisa de PredicateBuilder e MemberExpressionExtensions . Basta copiá-los para o seu projeto. Os filtros reutilizáveis podem ser estilizados como uma extensão (como em WhereOverlap), como um auxiliar estático ou como uma classe (como em UnderControlPayFilter).
Fiz alguns filtros reutilizáveis - GitHub , NuGet (inclui PredicateBuilder e MemberExpressionExtensions).