我首先使用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”(int)类型上,它都会给出错误。有人可以帮忙吗?欣赏是否有人告诉我为什么,为什么以及怎么样,因为我还在了解整个.net,mvc&amp; LINQ。
答案 0 :(得分:0)
我重新考虑你要做的事情是这样的:
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(以及实体框架也是如此)抱怨它无法执行转换为object
。
它可以处理的是投射到string
。所以:
Select(g => new string[] { g.Key.ToString(), g.Count().ToString() });
几乎没问题,但现在阵列初始化程序出现问题:&#34;数组类型&#39; System.String []&#39;无法在查询结果中初始化。考虑使用&#39; System.Collections.Generic.List`1 [System.String]&#39;相反。&#34; 这很简单:
Select(g => new List<string> { g.Key.ToString(), g.Count().ToString() });
现在可以将其翻译成SQL(至少通过实体框架,但我认为Linq to SQL也可以处理它)。因此,您应该将arrayExpressions
替换为:
var arrayExpressions = Expression.ListInit(Expression.New(typeof(List<string>)),
expressions.Select(expr => Expression.Call(expr, "ToString", null)).ToArray()
);
现在它有效。
总而言之,这是构建Linq查询的一种相当复杂的方式,难以调试甚至更难阅读。考虑使用泛型类型IQueryable并编写lambdas - 这是Linq
首先设计的内容。
如果你有或想要坚持使用手动表达式,我建议首先编写一个Linq查询(可能是一个更具体的情况),分析它生成的表达式,然后尝试手动创建这个表达式。
此外,将此表达式生成的SQL查询与应执行相同作业的简单linq查询进行比较 - 第一个将更复杂。