【问题标题】:Entity Framework - "Unable to create a constant value of type 'Closure type'..." error实体框架 - “无法创建‘闭包类型’类型的常量值...”错误
【发布时间】:2009-05-18 19:40:40
【问题描述】:

为什么会出现错误:

无法创建“闭包类型”类型的常量值。仅有的 支持原始类型(例如 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 方法上,对吧?有什么建议吗?

【问题讨论】:

    标签: linq entity-framework


    【解决方案1】:

    看起来您正在尝试执行与“WHERE...IN”条件等效的操作。查看 How to write 'WHERE IN' style queries using LINQ to Entities 以获取有关如何使用 LINQ to Entities 执行此类查询的示例。

    另外,我认为错误消息在这种情况下特别无用,因为.Contains 后面没有括号,这会导致编译器将整个谓词识别为 lambda 表达式。

    【讨论】:

    • 谢谢丹尼尔。相同的语法适用于普通的 Linq。那么,.Net 3.5 SP1 中的 EF 似乎存在问题,对吗?不带括号的包含等效于: where upperSearchList.All(x => (person.FirstName + person.LastName) .Contains(x)).ToList();
    • 如果我尝试 where upperSearchList.All(arg => arg == arg) 它会抛出同样的错误。所以问题出在 All 方法上……
    • LINQ to Entities 是一项很棒的技术,但是 SQL 翻译引擎是有限的。我无法将手放在官方文档上,但根据我的经验,如果查询不仅仅包含基本的数学和字符串/日期函数,它就不会起作用。你有机会查看我链接的那个帖子吗?它描述了将“WHERE..IN”类型查询转换为 LINQ to Entities 可以随后转换为 SQL 的形式的过程。
    • 您不能在 linq 中使用函数指针指向实体。提供者不知道如何从表达式树中挖掘出来以将其转换为 SQL。
    • @DanielPratt 您的链接已损坏
    【解决方案2】:

    在过去的 6 个月中,我一直在与 EF 3.5 的这个限制作斗争,虽然我不是世界上最聪明的人,但我很确定我可以在这个主题上提供一些有用的东西。

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

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

    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 表的架构。 Andrew Tappert(人)有两张身份证(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。

    【讨论】:

      【解决方案3】:

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

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

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

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

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

      现在 EF 不再使用复杂类型“Function”,而是使用简单类型(long)。而且效果很好!

      【讨论】:

        【解决方案4】:

        当我在 .All 函数中使用的数组对象为空时,我收到此错误消息 在我初始化数组对象(在你的情况下为upperSearchList)后,错误消失了 在这种情况下,错误消息具有误导性

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多