Expression.Call und Count

.net c# dynamic expression-trees linq

Frage

Ich suche nach einer Möglichkeit, dynamisch zu folgen:

var q = context.Subscription
               .Include("Client")
               .Include("Invoices")
                Where(s=>s.Client.Invoices.Count(i=>i.InvoiceID == SomeInt) > 0);

Ich möchte dynamisch Ausdruck für die linke Seite erstellen:

Expression left = s => s.Client.Invoices.Count(i => i.InvoiceID == iSomeVar); //!
Expression right = Expression.Constant(0);
var binary = Expression.GreaterThan(left, right);

Vielen Dank!

AKTUALISIERTE HINWEISE:

Bitte beachten Sie: Das Endergebnis muss sein

Expression<Func<T, bool>>

Einfache Version:

// To give clear idea, all what I want to achieve is to determine 
// whether specific record exists in reference table using known Path. 
// Ultimately I want to extend following function (which works great by 
// the way, but for simple operations)

static Expression CreateExpression<T>(string propertyPath, 
                                      object propertyValue, 
                                      ParameterExpression parameterExpression)
{
     PropertyInfo property = typeof(T).GetProperty(propertyName);
     MemberExpression left = Expression.Property(parameterExpression, property);
     ConstantExpression right = Expression.Constant(0);
     BinaryExpression binary = Expression.GreaterThan(left, right);

     return binary;
}

// And I want to call this function and get result exactly as shown below:

Expression result = 
           CreateExpression<Subscription>("Client.Invoices.InvoiceID", 
                                          theID,
                                          valueSelector.Parameters.Single());

// Where result will be: 
//       t => t.Client.Invoices.Count(i => i.InvoiceID == theID) > 0;

Erweiterte Version:

// 1) I'm using Silverlight 4, EF, RIA.

// 2) At the server side I have a function GetSubscriptionsByCriteria
//   that looks about it:

public IQueryable<Subscription> GetSubscriptionsByCriteria(...)
{
      var query = this.ObjectContext.Subscriptions.Include("Client")
                                                  .Include("Client.Invoices");
      var criteria = BuildCriteria(...);
      return query.Where(criteria)
}

// 3) BuildCriteria(...) function gathers Expressions and 
//    aggregates it into the single Expression with different 
//    AND/OR conditions, something like that:

public Expression<Func<Subscription, bool>> BuildCriteria(
                      List<SearchFilter> filters,
                      Expression<Func<Subscription, bool>> valueSelector)
{
    List<Expression> filterExpressions = new List<Expression>();
    ...
    Expression expr = CreateExpression<Subscription>(
                                   sfItem.DBPropertyName, 
                                   sfItem.DBPropertyValue, 
                                   paramExpression, 
                                   sf.SearchCondition);
    filterExpressions.Add(expr);
    ...

    var filterBody = 
        filterExpressions.Aggregate<Expression>(
                (accumulate, equal) => Expression.And(accumulate, equal));
   return Expression
           .Lambda<Func<Subscription, bool>>(filterBody, paramExpression);
}

// 4) Here is the simplified version of CreateExpression function:

 static Expression CreateExpression<T>(string propertyName, 
                                       object propertyValue, 
                                       ParameterExpression paramExpression)
 {
        PropertyInfo property = typeof(T).GetProperty(propertyName);
        ConstantExpression right = Expression.Constant(0);
        MemberExpression left = Expression.Property(paramExpression, property);

        return binary = Expression.Equals(left, right);
 }

Also, ich hoffe, es ist jetzt klar, warum brauche ich Expression für die linke Seite in meinem ursprünglichen Beitrag. Versuchen, dies so trocken wie möglich zu machen.

PS Um es hier nicht zu verwirrend zu machen, warum muss ich "Ñ'Expression.Call (...)" machen: Wenn ich den folgenden Code starte und ihn für DebugView sehe, merke ich Folgendes:

Expression<Func<Subscription, bool>> predicate = 
           t => t.Client.Invoices.Count(i => i.InvoiceID == 5) > 0;
BinaryExpression eq = (BinaryExpression)predicate.Body;
var left = eq.Left; // <-- See DEBUG VIEW
var right = eq.Right;   

// DEBUG VIEW:
// Arguments: Count = 2
//            [0] = {t.Client.Invoices}
//            [1] = {i => (i.InvoiceID == 5)}
// DebugView: ".Call System.Linq.Enumerable.Count(
//               ($t.Client).ClientInvoices,
//               .Lambda#Lambda1<System.Func`2[SLApp.Web.Invoice,System.Boolean]>)
//               .Lambda#Lambda1<System.Func`2[SLApp.Web.Invoice,System.Boolean]>
//               (SLApp.Web.ClientInvoice $i){ $i.ClientInvoiceID == 5 }"

Beliebte Antwort

Ich denke, das sollte dir näher bringen, wofür du hingehst:

static Expression<Func<T, bool>> CreateAnyExpression<T, T2>(string propertyPath, 
                                    Expression<Func<T2, bool>> matchExpression)
{
    var type = typeof(T);
    var parameterExpression = Expression.Parameter(type, "s");
    var propertyNames = propertyPath.Split('.');
    Expression propBase = parameterExpression;
    foreach(var propertyName in propertyNames)
    {
        PropertyInfo property = type.GetProperty(propertyName);
        propBase = Expression.Property(propBase, property);
        type = propBase.Type;
    }
    var itemType = type.GetGenericArguments()[0];
    // .Any(...) is better than .Count(...) > 0
    var anyMethod = typeof(Enumerable).GetMethods()
        .Single(m => m.Name == "Any" && m.GetParameters().Length == 2)
        .MakeGenericMethod(itemType);
    var callToAny = Expression.Call(anyMethod, propBase, matchExpression);
    return Expression.Lambda<Func<T, bool>>(callToAny, parameterExpression);
}

Nenn es so:

CreateAnyExpression<Subscription, Invoice>("Client.Invoices", i => i.InvoiceID == 1)

... ergibt den folgenden Expression<Func<Subscription,bool>> :

s => s.Client.Invoices.Any(i => (i.InvoiceID == 1)) 


Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow