Ho questa seguente domanda:
db.Users.AsQueryable()
.Where(u => u.Id = userResolver.LoggedUserId() && u.Packages.Where(p =>
p.StatusId == (int)PackageStatus.InProgress ||
p.StatusId == (int)PackageStatus.Delivered ||
p.StatusId == (int)PackageStatus.Shipped ||
p.StatusId == (int)PackageStatus.Waiting)
.Sum(p => p.Price) > u.MaxCredit)
.ToList()
Quello che sto cercando di ottenere è raggruppare tutti i controlli dello stato del pacchetto in metodi di estensione. Qualcosa del genere:
db.Users.AsQueryable()
.Where(u => u.Id = userResolver.LoggedUserId() &&
u.Packages.Where(p => p.IsShippedOrInProgress())
.Sum(p => p.Price) > u.MaxCredit)
.ToList()
//This is the extension method
public static bool IsShippedOrInProgress(this Package p) {
return p.StatusId == (int)PackageStatus.InProgress ||
p.StatusId == (int)PackageStatus.Delivered ||
p.StatusId == (int)PackageStatus.Shipped ||
p.StatusId == (int)PackageStatus.Waiting)
}
Quando visualizzo la query sql generata nel primo esempio, tutto sembra ok, ma quando sto usando il secondo approccio la parte della query che controlla lo stato non esiste.
Prova questo metodo che creerà Expression
, Package
come input e bool
come output:
public static System.Linq.Expressions.Expression<Func<Package, bool>> IsShippedOrInProgress()
{
return p => p.StatusId == ( int )PackageStatus.InProgress ||
p.StatusId == ( int )PackageStatus.Delivered ||
p.StatusId == ( int )PackageStatus.Shipped ||
p.StatusId == ( int )PackageStatus.Waiting);
}
Chiamalo così:
private void SomeMethod()
{
db.Users.AsQueryable()
.Where(u => u.Id = userResolver.LoggedUserId() &&
u.Packages.Where(IsShippedOrInProgress())
.Sum(p => p.Price) > u.MaxCredit)
.ToList()
}
Ho provato a scrivere questo nel blocco note. Quindi ci possono essere errori. Fatemi sapere nei commenti
public static Expression<Func<Package,bool>> IsShippedOrInProgress() {
// Compose the expression tree that represents the parameter to the predicate.
ParameterExpression p = Expression.Parameter(typeof(Package), "p");
// Compose left side of the expression i.e `p.StatusId`
Expression left = Expression.Call(p, typeof(Package).GetProperty("StatusId"));
// Compose right side of the expression i.e `(int)PackageStatus.InProgress` etc.
Expression exprInProgress = Expression.Constant((int)PackageStatus.InProgress);
Expression exprDelivered = Expression.Constant((int)PackageStatus.Delivered);
Expression exprShipped = Expression.Constant((int)PackageStatus.Shipped);
Expression exprWaiting = Expression.Constant((int)PackageStatus.Waiting);
// Compose left equals right side
Expression e1 = Expression.Equal(left, exprInProgress);
Expression e2 = Expression.Equal(left, exprDelivered);
Expression e3 = Expression.Equal(left, exprShipped);
Expression e4 = Expression.Equal(left, exprWaiting);
//Compose `p.StatusId == (int)PackageStatus.InProgress ||
// p.StatusId == (int)PackageStatus.Delivered ||
// p.StatusId == (int)PackageStatus.Shipped ||
// p.StatusId == (int)PackageStatus.Waiting`
Expression orConditions = Expressions.OrElse(Expression.OrElse(Expression.OrElse(e1,e2),e3),e4);
//Compose `p =>
// p.StatusId == (int)PackageStatus.InProgress ||
// p.StatusId == (int)PackageStatus.Delivered ||
// p.StatusId == (int)PackageStatus.Shipped ||
// p.StatusId == (int)PackageStatus.Waiting`
return Expression.Lambda<Func<Package, bool>>(orConditions, new ParameterExpression[] { p }));
}
Aggiornare
Il compilatore C # può generare alberi di espressione da espressioni lambda (o lambda a riga singola) . Si prega di verificare @ risposta Ankush