【问题标题】:How to do a Sum using Dynamic LINQ如何使用动态 LINQ 进行求和
【发布时间】:2013-07-05 13:28:14
【问题描述】:

我有以下与dynamic linq library 完美配合的:

string where = "Price < 5";
string orderby = "BookID ASC";
IQueryable<T> MyDataQueryable = _DataRawBase.AsQueryable<T>();
MyDataQueryable = MyDataQueryable.Where(where).OrderBy(orderby);

现在我想查询 MyDataQueryable 以对某些字段进行 SUM(也许是平均值)。

我该怎么做?

类似:

double mysum = MyDataQueryable.Sum("Price");  

会很好......

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    由于所有内容都是字符串类型,您可能想尝试一下:

    var myDataQueryable = _DataRawBase.AsQueryable<T>()
        .Sum("Price");
    

    使用以下扩展方法:

    public static object Sum(this IQueryable source, string member)
    {
        if (source == null) throw new ArgumentNullException(nameof(source));
        if (member == null) throw new ArgumentNullException(nameof(member));
    
        // The most common variant of Queryable.Sum() expects a lambda.
        // Since we just have a string to a property, we need to create a
        // lambda from the string in order to pass it to the sum method.
    
        // Lets create a ((TSource s) => s.Price ). First up, the parameter "s":
        ParameterExpression parameter = Expression.Parameter(source.ElementType, "s");
    
        // Followed by accessing the Price property of "s" (s.Price):
        PropertyInfo property = source.ElementType.GetProperty(member);
        MemberExpression getter = Expression.MakeMemberAccess(parameter, property);
    
        // And finally, we create a lambda from that. First specifying on what
        // to execute when the lambda is called, and finally the parameters of the lambda.
        Expression selector = Expression.Lambda(getter, parameter);
    
        // There are a lot of Queryable.Sum() overloads with different
        // return types  (double, int, decimal, double?, int?, etc...).
        // We're going to find one that matches the type of our property.
        MethodInfo sumMethod = typeof(Queryable).GetMethods().First(
            m => m.Name == "Sum"
                 && m.ReturnType == property.PropertyType
                 && m.IsGenericMethod);
    
        // Now that we have the correct method, we need to know how to call the method.
        // Note that the Queryable.Sum<TSource>(source, selector) has a generic type,
        // which we haven't resolved yet. Good thing is that we can use copy the one from
        // our initial source expression.
        var genericSumMethod = sumMethod.MakeGenericMethod(new[] { source.ElementType });
    
        // TSource, source and selector are now all resolved. We now know how to call
        // the sum-method. We're not going to call it here, we just express how we're going
        // call it.
        var callExpression = Expression.Call(
            null,
            genericSumMethod,
            new[] {source.Expression, Expression.Quote(selector)});
    
        // Pass it down to the query provider. This can be a simple LinqToObject-datasource,
        // but also a more complex datasource (such as LinqToSql). Anyway, it knows what to
        // do.
        return source.Provider.Execute(callExpression);
    }
    

    【讨论】:

    • 谢谢 - 我看到了那篇文章 - 但有没有其他(更简洁)的方法来获得总和?
    • 可能通过编写你自己的扩展方法,但不是默认的。
    • 好的-但是,该语句似乎仍然不起作用...这是我作为测试输入的内容: var aq = MyDataQueryable.Select("new (Sum(Price) as Total) ");那么错误是:“MyAlbum”类型中不存在适用的方法“Sum”(在索引 5 处)
    • 呼——成功了!! - 我将其更改为 var test = _DataRawBase.AsQueryable().Sum("Price"); (否则铸造问题)但 var 包含我的总和!非常感谢!今晚晚些时候将学习这个例子。
    • 添加了一些关于其工作原理的简要信息。希望对您有所帮助,如果您还有其他问题,请提出。享受
    【解决方案2】:

    这段代码对我有用:

    浮动? fSum = qryQueryableData.Select("Price").Cast().Sum();

    其中“价格”是“浮动”类型的列?

    解释可用here

    【讨论】:

      【解决方案3】:

      我还需要扩展 Caramiriel 的答案以处理字段:

          public static object Sum(this IQueryable source, string member)
          {
              if (source == null) throw new ArgumentNullException("source");
              if (member == null) throw new ArgumentNullException("member");
      
              // Properties
              PropertyInfo property = source.ElementType.GetProperty(member);
              FieldInfo field = source.ElementType.GetField(member);
      
              ParameterExpression parameter = Expression.Parameter(source.ElementType, "s");
              Expression selector = Expression.Lambda(Expression.MakeMemberAccess(parameter, (MemberInfo)property ?? field), parameter);
              // We've tried to find an expression of the type Expression<Func<TSource, TAcc>>,
              // which is expressed as ( (TSource s) => s.Price );
      
              // Method
              MethodInfo sumMethod = typeof(Queryable).GetMethods().First(
                  m => m.Name == "Sum"
                      && (property != null || field != null)
                      && (property == null || m.ReturnType == property.PropertyType) // should match the type of the property
                      && (field == null || m.ReturnType == field.FieldType) // should match the type of the property
                      && m.IsGenericMethod);
      
              return source.Provider.Execute(
                  Expression.Call(
                      null,
                      sumMethod.MakeGenericMethod(new[] { source.ElementType }),
                      new[] { source.Expression, Expression.Quote(selector) }));
          }
      

      【讨论】:

        【解决方案4】:

        尝试使用 lambda 表达式:

        double mysum = MyDataQueryable.Sum(mdq => mdq.Price); 
        

        【讨论】:

        • 谢谢 - 但这里的想法是我不知道我正在处理什么类型,因此动态 linq 库。因此我无法使用标准 lambda...
        猜你喜欢
        • 1970-01-01
        • 2016-04-02
        • 2011-06-03
        • 1970-01-01
        • 1970-01-01
        • 2013-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多