Я ищу способ динамически выполнять следующие действия:
var q = context.Subscription
.Include("Client")
.Include("Invoices")
Where(s=>s.Client.Invoices.Count(i=>i.InvoiceID == SomeInt) > 0);
Я бы хотел динамически построить выражение для левой стороны:
Expression left = s => s.Client.Invoices.Count(i => i.InvoiceID == iSomeVar); //!
Expression right = Expression.Constant(0);
var binary = Expression.GreaterThan(left, right);
Спасибо!
ОБНОВЛЕННЫЕ ПРИМЕЧАНИЯ:
Обратите внимание: конечный результат должен быть
Expression<Func<T, bool>>
Простая версия:
// 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;
Расширенная версия:
// 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);
}
Итак, я надеюсь, теперь понятно, зачем мне нужно выражение для левой стороны в моем исходном посте. Попытка сделать это как можно более сухим.
P.S. Чтобы это не было слишком запутанным, вот почему я думаю, что мне нужно сделать выражение. Вызов (...)
Когда я запускаю следующий код и ломаю его, чтобы увидеть DebugView, я замечаю это:
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 }"