防爆pression.Call和计数 [英] Expression.Call and Count

查看:200
本文介绍了防爆pression.Call和计数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一个方式做动态如下:

 变种Q = context.Subscription
               .INCLUDE(客户)
               .INCLUDE(发票)
                其中,(S => s.Client.Invoices.Count(ⅰ=> i.InvoiceID == SomeInt)大于0);
 

我要动态地构建EX pression的左侧:

 防爆pression左= S => s.Client.Invoices.Count(ⅰ=> i.InvoiceID == iSomeVar); //!
防爆pression右=前pression.Constant(0);
VAR二进制=前pression.GreaterThan(左,右);
 

谢谢!

修订注意:

请注意:最终的结果一定是

 防爆pression< Func键< T,布尔>>
 

简易版:

  //给出明确的想法,所有我想要实现的是确定
//使用已知的路径在引用表中是否具体的记录存在。
//最后,我想对下面的函数(它的伟大工程
//的方式,但对于简单的操作)

静态防爆pression CreateEx pression< T>(字符串的PropertyPath,
                                      对象为PropertyValue,
                                      ParameterEx pression parameterEx pression)
{
     的PropertyInfo财产= typeof运算(T).GetProperty(propertyName的);
     MemberEx pression左=前pression.Property(parameterEx pression,财产);
     ConstantEx pression右=前pression.Constant(0);
     BinaryEx pression二进制=前pression.GreaterThan(左,右);

     返回二进制;
}

//我要调用这个函数,并得到确切结果如下图所示:

防爆pression结果=
           CreateEx pression<认购>(Client.Invoices.InvoiceID
                                          theID,
                                          valueSelector.Parameters.Single());

//如果结果将是:
// T => t.Client.Invoices.Count(I => i.InvoiceID == theID)> 0;
 

扩展版:

  // 1)我使用Silverlight 4中,EF,RIA。

// 2)在服务器端我有一个函数Ge​​tSubscriptionsByCriteria
//看起来这件事:

公众的IQueryable<认购> GetSubscriptionsByCriteria(...)
{
      VAR的查询= this.ObjectContext.Subscriptions.Include(客户)
                                                  .INCLUDE(Client.Invoices);
      VAR标准= BuildCriteria(...);
      返回query.Where(标准)
}

// 3)BuildCriteria(...)函数集防爆pressions和
//聚集入单个实施例pression具有不同
// AND / OR条件,这样的事情:

公共防爆pression< Func键<认购,布尔>> BuildCriteria(
                      名单< SearchFilter>过滤器,
                      防爆pression< Func键<认购,布尔>> valueSelector)
{
    名单<防爆pression> filterEx pressions =新的名单,其中,前pression>();
    ...
    防爆pression EXPR = CreateEx pression<认购>(
                                   sfItem.DBPropertyName,
                                   sfItem.DBPropertyValue,
                                   paramEx pression,
                                   sf.SearchCondition);
    filterEx pressions.Add(表达式);
    ...

    VAR filterBody =
        filterEx pressions.Aggregate<防爆pression>(
                (积累,等于)=>防爆pression.And(积累,等于));
   返回前pression
           .Lambda< Func键<认购,布尔>>(filterBody,paramEx pression);
}

// 4)这里是CreateEx pression功能的简化版本:

 静态防爆pression CreateEx pression< T>(字符串propertyName的,
                                       对象为PropertyValue,
                                       ParameterEx pression paramEx pression)
 {
        的PropertyInfo财产= typeof运算(T).GetProperty(propertyName的);
        ConstantEx pression右=前pression.Constant(0);
        MemberEx pression左=前pression.Property(paramEx pression,财产);

        返回二进制=前pression.Equals(左,右);
 }
 

所以,我希望这是明确的,现在为什么需要防爆pression的左侧在原来的职位。试图使这个尽可能的干燥。

P.S。不要弄得太混乱这里就是为什么我认为我需要做ёExpression.Call(...)ё: 当我运行下面的code和打破它,看看我的DebugView注意到这一点:

 防爆pression< Func键<认购,布尔>> predicate =
           T => t.Client.Invoices.Count(ⅰ=> i.InvoiceID == 5)> 0;
BinaryEx pression EQ =(BinaryEx pression)predicate.Body;
VAR左= eq.Left; //<  - 看到调试视图
无功权= eq.Right;

//调试视图:
//参数:数= 2
// [0] = {} t.Client.Invoices
// [1] = {I => (i.InvoiceID == 5)}
// DebugView中:.CALL System.Linq.Enumerable.Count(
//($ t.Client).ClientInvoices,
// .Lambda#Lambda1&其中; System.Func`2 [SL​​App.Web.Invoice,可选System.Boolean]≥)
// .Lambda#Lambda1&其中; System.Func`2 [SL​​App.Web.Invoice,可选System.Boolean]≥
//(SLApp.Web.ClientInvoice $ I){$ i.ClientInvoiceID == 5}
 

解决方案

我想这应该让你更接近你要去什么:

 静态防爆pression< Func键< T,布尔>> CreateAnyEx pression< T,T2>(字符串的PropertyPath,
                                    防爆pression< Func键< T2,布尔>> matchEx pression)
{
    VAR类型= ty​​peof运算(T);
    变种parameterEx pression =实施例pression.Parameter(类型,S);
    变种propertyNames = propertyPath.Split('。');
    防爆pression propBase = parameterEx pression;
    的foreach(在propertyNames VAR propertyName的)
    {
        的PropertyInfo财产= type.GetProperty(propertyName的);
        propBase =前pression.Property(propBase,属性);
        TYPE = propBase.Type;
    }
    变种ITEMTYPE = type.GetGenericArguments()[0];
    //。任何(...)比.Count之间(...)&GT更好; 0
    VAR anyMethod = typeof运算(可枚举).GetMethods()
        。单(M => m.Name ==任何&放大器;&安培; m.GetParameters()长度== 2)
        .MakeGenericMethod(ITEMTYPE);
    VAR callToAny =前pression.Call(anyMethod,propBase,matchEx pression);
    返回前pression.Lambda< Func键< T,布尔>>(callToAny,parameterEx pression);
}
 

调用它是这样的:

  CreateAnyEx pression<认购,发票>(Client.Invoices,I => i.InvoiceID == 1)
 

......将产生以下防爆pression< Func键<认购,布尔>>

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

I'm looking for a way to do following dynamically:

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

I would like to build expression dynamically for the left side:

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

Thanks!

UPDATED NOTES:

Please note: The end result must be

Expression<Func<T, bool>>

Simple 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;

Extended 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);
 }

So, I hope it's clear now why do I need Expression for the left side in my original post. Trying to make this as DRY as possible.

P.S. Not to make it too confusing here is why I think I need to do ёExpression.Call(...)ё: When I run following code and break it to see DebugView I notice this:

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 }"

解决方案

I think this should get you closer to what you're going for:

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);
}

Calling it like this:

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

... yields the following Expression<Func<Subscription,bool>>:

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

这篇关于防爆pression.Call和计数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆