实体框架-“无法创建类型为'结算类型'的常量值……”错误


79

为什么会出现错误:

无法创建类型为“结算类型”的常量值。在此上下文中仅支持原始类型(例如Int32,String和Guid)。

当我尝试枚举以下Linq查询时?

IEnumerable<string> searchList = GetSearchList();
using (HREntities entities = new HREntities())
{
   var myList = from person in entities.vSearchPeople
   where upperSearchList.All( (person.FirstName + person.LastName) .Contains).ToList();
}

更新:如果我尝试以下方法只是为了找出问题所在,则会收到相同的错误:

where upperSearchList.All(arg => arg == arg) 

看来问题出在All方法上,对不对?有什么建议?

Answers:


68

似乎您正在尝试执行相当于“ WHERE ... IN”条件的操作。查看如何使用LINQ to Entities编写“ WHERE IN”样式的查询,以获取有关如何使用LINQ to Entities进行该类型查询的示例。

另外,我认为该错误消息在这种情况下尤其无济于事,因为.Contains后面没有括号,这会使编译器将整个谓词识别为lambda表达式。


谢谢丹尼尔。相同的语法在普通Linq上也可以正常工作。因此,看起来像问题出在.Net 3.5 SP1中的EF对吗?不带括号的Contains等效于:where upperSearchList.All(x =>(person.FirstName + person.LastName).Contains(x))。ToList();
Gus Cavalcanti

如果我尝试在upperSearchList.All(arg => arg == arg)的地方抛出相同的错误。所以问题出在All方法上……
Gus Cavalcanti

2
LINQ to Entities是一项很棒的技术,但是SQL转换引擎受到限制。我不能把手放在官方文档上,但是根据我的经验,如果查询不仅仅包含基本数学和字符串/日期函数,那么它将无法正常工作。您是否有机会查看我链接的帖子?它描述了将“ WHERE..IN”类型查询转换为LINQ to Entities然后可以转换为SQL的形式的过程。
丹尼尔·普拉特

您不能在linq中使用实体的函数指针。提供程序不知道如何将其从表达式树中挖掘出来以将其转换为SQL。
Sinaesthetic

@DanielPratt您的链接已断开
Mick

11

在过去的6个月中,我一直在使用EF 3.5与这一限制作斗争,尽管我不是世界上最聪明的人,但是我敢肯定,在这个问题上我可以提供一些有用的东西。

通过生长50英里高的“ OR风格”表达式树生成的SQL将导致不良的查询执行计划。我正在处理几百万行,影响很大。

我发现有一个小技巧,可以做一个SQL'in',如果您只是通过id查找一堆实体,这对您有帮助:

private IEnumerable<Entity1> getByIds(IEnumerable<int> ids)
{
    string idList = string.Join(",", ids.ToList().ConvertAll<string>(id => id.ToString()).ToArray());
    return dbContext.Entity1.Where("it.pkIDColumn IN {" + idList + "}");
}

其中pkIDColumn是Entity1表的主键ID列名称。

但是请保持阅读!

很好,但是它要求我已经具有需要查找的ID。有时候,我只是想表达自己的观点,以达到其他关系,而我所拥有的就是这些联系关系的标准。

如果我有更多的时间,我会尝试用视觉来表示它,但是我不那么研究这一句话:考虑一个具有Person,GovernmentId和GovernmentIdType表的模式。安德鲁·塔珀特(人)有两张身份证(GovernmentId),一张来自俄勒冈州(GovernmentIdType),另一张来自华盛顿(GovernmentIdType)。

现在从中生成一个edmx。

现在,假设您要查找具有特定ID值的所有人员,例如1234567。

这可以通过单击以下单个数据库来完成:

dbContext context = new dbContext();
string idValue = "1234567";
Expression<Func<Person,bool>> expr =
    person => person.GovernmentID.Any(gid => gid.gi_value.Contains(idValue));

IEnumerable<Person> people = context.Person.AsQueryable().Where(expr);

您在这里看到子查询了吗?生成的sql将使用“ joins”而不是子查询,但是效果是相同的。如今,无论如何,SQL Server都会将子查询优化为隐藏的联接,但是无论如何...

这项工作的关键是表达式中的.Any。


8

我发现了错误的原因(我正在使用Framework 4.5)。问题是,EF在“包含”参数中传递的复杂类型无法转换为SQL查询。EF只能在SQL查询中使用简单类型,例如int,string ...

this.GetAll().Where(p => !assignedFunctions.Contains(p))

GetAll提供具有复杂类型的对象的列表(例如:“ Function”)。因此,我将在这里尝试在我的SQL查询中接收这种复杂类型的实例,这自然是行不通的!

如果我可以从列表中提取适合搜索的参数,则可以使用:

var idList = assignedFunctions.Select(f => f.FunctionId);
this.GetAll().Where(p => !idList.Contains(p.FunktionId))

现在,EF不再具有复杂的“函数”类型,而是具有简单的类型(长整数)。而且效果很好!


0

当我在.All函数中使用的数组对象为null时,我收到此错误消息。初始化数组对象(在您的情况下为upperSearchList)后,错误消失了。

其中upperSearchList.All(arg => person.someproperty.StartsWith(arg)))

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.