【问题标题】:LINQ to Entity Any() with related Object CollectionLINQ to Entity Any() 与相关的对象集合
【发布时间】:2014-06-27 10:59:37
【问题描述】:

首先,让我说我已经研究过这个问题并阅读了以下堆栈溢出文章,但它们都没有真正解决这种情况。

情况

我有两节课

public class Section{
    public string SchoolId{get;set;}
    public string CourseId{get;set;}
    public string SectionId{get;set;}
}

public class RelatedItem{
    public string SchoolId{get;set;}
    public string CourseId{get;set;}
    public string SectionId{get;set;}
    //..
}

我有一个来自一个来源的Section 数组,是一个实际的对象集合。

RelatedItem 我正在通过针对 DbContext 的 LINQ to Entities 调用。

我的目标是根据我从其他来源获得的部分获取所有相关项。

我正在写这样的查询

Section[] mySections = GetSections();    //Third Party Source
IQueryable<RelatedItem> relatedItems = DbContext.RelatedItems
    .Where(r=>
        mySections.Any(s=> s.SchoolId == r.SchoolId &&
                           s.CourseId == r.CourseId &&
                           s.SectionId == r.SectionId)
    );

问题

在运行时,我收到以下错误

无法创建类型的常量值 '项目命名空间.Section'。只有原始类型或 在此上下文中支持枚举类型。

我找到了解决方法,但它涉及执行以下操作,但它没有利用我的任何表索引。

var sectionIds = sections.Select(s=>string.Concat(s.SchoolId, "|",s.CourseId, "|",s.SectionId));
IQueryable<RelatedItem> relatedItems = DbContext.RelatedItems
        .Where(r=>
            sectionIds.Contains(string.Concat(r.SchoolId, "|",r.CourseId, "|",r.SectionId))
        );

这段代码有效,目前速度非常快(但这是开发,我的记录数很少)。除了将我的相关项目转换为内存中的集合之外,还有其他建议吗?

【问题讨论】:

  • 尝试添加 ToList() DbContext.RelatedItems.ToList().Where(r=> 告诉我进展如何。
  • 一个建议更改数据库方案并添加代理 PK 而不是复合。
  • @LIUFA,您是否建议将整个数据库表(可能是 100 万行)加载到内存集合中?
  • @HamletHakobyan 这只是一个测试,下一步是实现 IEquitable

标签: c# sql linq entity-framework-6


【解决方案1】:

尝试改用Contains

Section[] mySections = GetSections();    //Third Party Source

IQueryable<RelatedItem> relatedItems = DbContext.RelatedItems.Where(r=>
    mySections.Select(s => s.SchoolId).Contains(r.SchoolId) &&
    mySections.Select(s => s.CourseId).Contains(r.CourseId) &&
    mySections.Select(s => s.SectionId).Contains(r.SectionId)
);

Contains 应转换为 SQL 中的 WHERE IN 子句。

如果使用 .NET 3.5 和 LINQ to Entities,这将不起作用,因为它没有在该版本中实现。

【讨论】:

  • 如果 RelatedItems 中的一行具有与 Sections 中的多个不同行相关的键怎么办?我想它不会给我们正确的结果。
  • @OleksiiAza,我同意。有可能有多个相关项目,如果所有三个键没有一起使用,则会出现额外的记录。
  • 逻辑是,如果section中的任何一行有schoolid,sections中的任何一行都有courseid,sections中的任何一行都有sectionid……那么它就会被选中。因此,所有 3 个都必须在部分集合中的某一行中。但是我注意到,在 OP 原始帖子中,他在一个 linq 查询中具有 and 条件,而在另一个中具有 or 条件。那么它是什么?
  • 这不是 OR。我取值(SchoolIdCourseIdSectionId)并创建一个单独的管道分隔字符串。然后我使用Contains比较这两个字符串。
  • 这种语法似乎违反直觉,但它可以工作并生成 WHERE IN。它确实需要将部分详细信息打包到元组集合中并执行包含。
【解决方案2】:

解决这个问题的正确方法是实现 IEquitable。这是一个关于如何做到这一点的例子Does LINQ to Entities support IEquatable in a 'where' clause predicate?
实现 Equals() 和 GetHashCode() 时的一个提示不要调用任何 .NET 方法(如 getType()),只比较原语 SchoolId、CourseId、SectionId,它应该被转换为表达式树并正常工作。

【讨论】:

  • 我已经完成并实现了 IEquitable,并使用了 Where,但我仍然收到无法在 Linq to Entities 中使用 Section 的错误
  • @kghantous 请张贴代码,我明天某个时候去看看。
  • @kghantous 看看这篇文章。 stackoverflow.com/questions/326321/…
  • 您自己的回答告诉我们 IEquatable 不受 L2E 支持,因此这永远无法回答问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-11
  • 2010-12-03
  • 1970-01-01
相关资源
最近更新 更多