使用 EF 5.0 返回缺少多对多记录的对象

Posted

技术标签:

【中文标题】使用 EF 5.0 返回缺少多对多记录的对象【英文标题】:Return objects missing records in many to many using EF 5.0 【发布时间】:2013-01-02 17:32:05 【问题描述】:

鉴于下面的架构,我正在尝试构建一个 EF 查询,该查询返回缺少所需表单的联系人。每个联系人都有一个与 FormTypes 集合相关的 ContactType。每个联系人都必须至少有一个表单(在 ContactForm 中)与其 ContactType 相关的 FormTypes。

EF 从下面的 linq 查询生成的查询适用于 Sql Server,但不适用于 Oracle。

var query = ctx.Contacts.Where (c => c.ContactType.FormTypes.Select (ft => ft.FormTypeID)
                            .Except(c => c.Forms.Select(f => f.FormTypeID)).Any());

我正在重构数据层,以便使用 Devart 的 dotConnect 数据提供程序对 Sql Server 工作的所有 EF 查询也对 Oracle 工作。

Oracle 抛出的错误是 ORA-00904: "Extent1"."ContactID": invalid identifier。

问题在于,Oracle 显然不支持从 2 级或更深的嵌套子查询中的查询引用表列。 Oracle 抛出的行是在引用“Extent1”.“ContactID”的除外(或减号)子查询中。 “Extent1”是在查询顶层定义的联系人的别名。 Here is Devart's explanation of the Oracle limitation.

我为许多查询解决此问题的方法是重写它们以使用 SelectMany() 和在某些情况下使用 Join( )。这往往会使发送到数据库服务器的查询变得扁平化,并最大限度地减少或消除 EF 产生的子查询。 Here is a similar issue solved using a left outer join.

“Extent1”.“ContactID”列存在,EF 和 Devart 生成的查询的命名语法不是问题。

任何关于如何重写此查询的想法将不胜感激。目标是一个查询,该查询返回联系人缺少适用于 Oracle 和 Sql Server 的联系人的 ContactType 所需的 FormType 表单。

【问题讨论】:

【参考方案1】:

以下实体框架查询返回在针对 Sql Server 和 Oracle 进行查询时缺少其 ContactType 所需 FormTypes 的联系人的所有 ContactID。

var contactNeedsFormTypes = 
       from c in Contacts 
       from ft in c.ContactType.FormTypes
       select new  ft.FormTypeID, c.ContactID;

var contactHasFormTypes = 
       from c in Contacts
       from f in c.Forms
       select new  c.ContactID, f.FormTypeID;

var contactsMissingFormTypes = 
       from n in contactNeedsFormTypes
       join h in contactHasFormTypes
          on new n.ContactID, n.FormTypeID equals new h.ContactID, h.FormTypeID
              into jointable
              where jointable.Count()==0
select n.ContactID;

contactsMissingFormTypes.Distinct();

【讨论】:

以上是关于使用 EF 5.0 返回缺少多对多记录的对象的主要内容,如果未能解决你的问题,请参考以下文章

EF Core 5.0 - 更新 ASP.NET Core Web API 中的多对多实体

EF更新多对多关系表中记录的时候,无法更新关系表的问题。

EF Code First 没有实体的多对多关系

EF CodeFirst系列---配置1对1,1对多,多对多关系

EF Core:LINQ 选择“多对多”到“多对多”

EF Core 5,删除多对多关系