簡體   English   中英

使用動態表達式的組的IQueryable LINQ轉換錯誤

[英]IQueryable LINQ cast error for group by using dynamic expression

我先使用C#、. Net 4.5,MVC,實體框架5.0和代碼。 我在使用devexpress的示例之一時遇到錯誤。 問題在於獲取groupby值和聚合(計數)查詢的列表。

該錯誤是無法將類型'System.Int32'強制轉換為類型'System.Object'。 LINQ to Entities僅支持大小寫EDM基本或枚舉類型

實體/表是

public class Test
{
    [Key]
    public int ID { get; set; }
    public string Name { get; set; }
    public DateTime SubmitDate { get; set; }
    public int TotalValue { get; set; }
}

有關獲取分組信息的測試代碼

public void GetGroupInfo() 
{
    GetGroupInfo(Context.Tests, "TotalValue");
    GetGroupInfo(Context.Tests, "Name");
}

public static void GetGroupInfo(this IQueryable query, string fieldName)
{
    CriteriaToExpressionConverter converter = new CriteriaToExpressionConverter();

    var rowType = query.ElementType;
    query = query.MakeGroupBy(converter, new OperandProperty(fieldName));
    query = query.MakeOrderBy(converter, new ServerModeOrderDescriptor(new OperandProperty("Key"), false));

    /*
      i think the problem is from here
    */
    query = ApplyExpression(query, rowType, "Key", "Count");

    // ignore the GridViewGroupInfo, just a class to store the value
    var list = new List<GridViewGroupInfo>();
    foreach (var item in query)
    {
        var obj = (object[])item;
        list.Add(new GridViewGroupInfo() {KeyValue=obj[0], DataRowCount =(int)obj[1]});
    }
}

static IQueryable ApplyExpression(IQueryable query, Type rowType, params string[] names)   
{
    var parameter = Expression.Parameter(query.ElementType, string.Empty);
    var expressions = names.Select(n => query.GetExpression(n, rowType, parameter));
    var arrayExpressions = Expression.NewArrayInit(
        typeof(object),
        expressions.Select(expr=>Expression.Convert(expr,typeof(object))).ToArray()
    );
    var lambda = Expression.Lambda(arrayExpressions, parameter);

    var expression = Expression.Call(
        typeof(Queryable),
        "Select",
        new Type[] { query.ElementType, lambda.Body.Type },
        query.Expression,
        Expression.Quote(lambda)
    );
    return query.Provider.CreateQuery(expression);
}

static Expression GetExpression(this IQueryable query, string commandName, Type rowType,    ParameterExpression parameter)
{
    switch (commandName)
    {
        case "Key":
            return Expression.Property(parameter, "Key");
        case "Count":
            return Expression.Call(typeof(Enumerable), "Count", new Type[] { rowType }, parameter);
    }
    return null;
}

無論分組是在“名稱”(字符串)類型還是“ TotalValue”(整數)類型上,它都給我錯誤。 有人可以幫忙嗎? 感謝是否有人告訴我原因,原因和方式,因為我仍在學習整個.net,mvc和linq。

我確認您要執行的操作是這樣的:

Context.Tests.GroupBy(t => t.TotalValue).Select(g => new { Key = g.Key, Count = g.Count() });
Context.Tests.GroupBy(t => t.Name).Select(g => new { Key = g.Key, Count = g.Count() });

但是使用手動創建的Expressions

您實際創建的以及問題所在是最后的選擇:

 var arrayExpressions = Expression.NewArrayInit(
    typeof(object),
    expressions.Select(expr=>Expression.Convert(expr,typeof(object))).ToArray()
);

將為您提供相當於:

Select(g => new object[] { (object)g.Key, (object)g.Count() });

確實,嘗試執行這樣的查詢將導致LINQ to Entities(就此而言,也是Entity Framework)抱怨它無法進行object

它可以處理的是轉換為string 所以:

Select(g => new string[] { g.Key.ToString(), g.Count().ToString() });

幾乎可以,但是現在數組初始化程序存在問題: “無法在查詢結果中初始化數組類型'System.String []'。請考慮使用'System.Collections.Generic.List`1 [System.String ]”。 這很容易:

Select(g => new List<string> { g.Key.ToString(), g.Count().ToString() });

現在可以將其轉換為SQL(至少是通過Entity Framework,但我想Linq to SQL也可以處理)。 因此,您應該使用以下arrayExpressions替換arrayExpressions

var arrayExpressions = Expression.ListInit(Expression.New(typeof(List<string>)),
                expressions.Select(expr => Expression.Call(expr, "ToString", null)).ToArray()
            );

現在就可以了。

總而言之,這是一種構建Linq查詢的相當復雜的方法,很難調試,甚至更難閱讀。 考慮使用通用類型IQueryable並編寫lambda-這是Linq首先設計的目的。 如果您有或想要堅持使用手動表達式,我建議您先編寫一個Linq查詢(可能針對更具體的情況),分析它生成的表達式,然后嘗試手動創建此表達式。

另外,將該表達式生成的SQL查詢與應該執行相同工作的簡單linq查詢進行比較-第一個查詢將更加復雜。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM