【问题标题】:Entity Framework: Unable to create a constant value of type 'System.Collections.Generic.IList`1'实体框架:无法创建类型为“System.Collections.Generic.IList`1”的常量值
【发布时间】:2017-02-07 15:57:06
【问题描述】:

今天这给我带来了无穷无尽的问题。我有这个简单的查询

var result =
    DataContext.Accommodations.Where(a => 
        (criteria.MinPrice == null || a.AccommodationRates.Any(r => r.From >= criteria.MinPrice)) &&
        (criteria.MaxPrice == null || a.AccommodationRates.Any(r => r.To <= criteria.MaxPrice)) &&
        (criteria.Locations == null || criteria.Locations.Count == 0 || a.AccommodationPlaceJoins.Any(j => criteria.Locations.Contains(j.Place.PlaceName)))
);

这个查询的最后一行给我带来了问题

(criteria.Locations == null ||
 criteria.Locations.Count == 0 ||
 a.AccommodationPlaceJoins.Any(j => criteria.Locations.Contains(j.Place.PlaceName)))

它给出的错误是

无法创建类型的常量值 'System.Collections.Generic.IList`1'。只有原始类型('例如 在此上下文中支持 Int32、String 和 Guid')。

我什至没有尝试创建列表。我在这里要做的就是带回与一个地方相关联的住宿(地方表中的地名通过AccommodationPlaceJoin表链接到住宿表)等于条件中的任何一个地名.Locations(IList 类型)。

我试过把这一行改成这样,但没用。

(criteria.Locations == null ||
 criteria.Locations.Count == 0 ||
 a.AccommodationPlaceJoins.Any(j => criteria.Locations.Any(l => l == j.Place.PlaceName)))

【问题讨论】:

    标签: c# lambda entity-framework-4 linq-to-entities


    【解决方案1】:

    EF 无法创建的常量值是null,用于比较criteria.Locations == null。您需要将查询分成两种情况,并检查查询之外的空列表,例如:

    var result = DataContext.Accommodations.Where(a => 
        (criteria.MinPrice == null || 
            a.AccommodationRates.Any(r => r.From >= criteria.MinPrice)) &&
        (criteria.MaxPrice == null ||
            a.AccommodationRates.Any(r => r.To <= criteria.MaxPrice)));
    
    if (criteria.Locations != null && criteria.Locations.Count > 0)
    {
        result = result.Where(a => a.AccommodationPlaceJoins
            .Any(j => criteria.Locations.Contains(j.Place.PlaceName)));
    }
    

    编辑

    顺便说一句:在我看来,编写整个查询会使其更具可读性,并将简化必须发送到数据库的 SQL:

    IQueryable<Accommodation> result = DataContext.Accommodations;
    
    if (criteria.MinPrice != null)
        result = result.Where(a => a.AccommodationRates
            .Any(r => r.From >= criteria.MinPrice));
    
    if (criteria.MaxPrice != null)
        result = result.Where(a => a.AccommodationRates
            .Any(r => r.To <= criteria.MaxPrice));
    
    if (criteria.Locations != null && criteria.Locations.Count > 0)
        result = result.Where(a => a.AccommodationPlaceJoins
            .Any(j => criteria.Locations.Contains(j.Place.PlaceName)));
    

    【讨论】:

    • 哇,多么棒的答案。太感谢了。我进行了很多错误的询问。感谢 +1 并接受了答案和最喜欢的问题。难怪你有近 29K 点。为什么会发生这种情况?
    • 我正在根据您的可读性建议进行重构。谢谢。
    • @SachinKainth:发生异常是因为在 LINQ to Entities 中,查询中的每个表达式和表达式片段都必须可翻译成 SQL。 criteria.Locations == null 的比较不会在客户端 (= .NET) 端执行,而是 EF 也希望将其转换为 SQL,然后数据库应该执行比较。但是数据库不知道如何比较 .NET/CLR 对象引用,它只能检查原始类型,如字符串、int 等。NULL。无法或不支持转换为 SQL -> 异常。
    • 我现在明白了 - 非常感谢。
    猜你喜欢
    • 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
    相关资源
    最近更新 更多