【问题标题】:how to query a many to many for the absence of records using EF5如何使用 EF5 查询多对多是否缺少记录
【发布时间】:2012-12-12 09:32:46
【问题描述】:

假设纯多对多,其中主键是两个外键的组合。例如,Northwind 中的“Employee Privileges”具有 EmployeeID 和 PrivilegeID。这个 m2m 显然将 Employees 表与 Privilege 表相关联。

我需要使用 EF 编写一个查询,该查询返回所有与指定 PrivilegeID 无关的员工,无论它是否与其他 PrivilegeID 相关。

我有一个 EF 查询,它使用 Except() 可用于 Sql Server,但它不适用于 Oracle。

如果我在 t-sql 中编写查询,我会编写一个查询来过滤具有所需特权的员工特权“请参阅下面的 EmpPrivQuery”。然后,我会将 EmpPrivQuery 加入到 Employee 中,如EmployeesMissingPrivileges 中所示,以完成过滤器。

我们目前有 Employee 和 Privilege 模型以及关系属性来创建多对多表。该项目首先使用 EF 代码创建架构。

这可以用 EF 连接语法来完成吗?可以不为EmployeePrivilege表创建Entity模型吗?

EmpPrivQuery:
SELECT [Employee Privileges].[Employee ID], [Employee Privileges].[Privilege ID] 
FROM [Privileges] INNER JOIN [Employee Privileges] ON Privileges.[Privilege ID] = [Employee Privileges].[Privilege ID]
WHERE (((Privileges.[Privilege Name])="P3"));


EmployeesMissingPrivileges:
SELECT EmpPrivQuery.[Employee ID], Employees.*
FROM Employees LEFT JOIN EmpPrivQuery ON Employees.ID = EmpPrivQuery.[Employee ID]
WHERE (((EmpPrivQuery.[Employee ID]) Is Null));

此块在原始帖子中,但使问题变得模糊。保留评论上下文。 我使用 Devart dotConnect 作为 Oracle 数据提供者。 Oracle 抛出的错误是ORA-00904: "Extent1"."EmployeeID": invalid identifier。在调整为 sql server 编写的代码库以针对 oracle 工作时,这是我需要解决的常见错误。在大多数情况下,我已经能够通过重写查询来解决它,以便使用 SelectMany() 将与其他表的关系从 WHERE 谓词(它很容易成为动态)移到查询的主体中。这往往会使发送到数据库服务器的查询变得扁平化,而 Oracle 似乎需要这样做。

【问题讨论】:

  • 错误提示你查询的列"EmployeeID"不存在。这很可能是因为您在引号中使用了它;默认情况下,所有对象名称都是大写的,Oracle 明确不鼓励对它们进行大小写。您是否尝试过仅使用 employeeid 代替(如果您的列名没有大小写?)
  • 好吧,显示您尝试过的查询。比你多云的描述清楚得多。你的意思是 !Any() 构造没有完成这项工作?
  • 感谢您的回复。案例不是问题,并且该列确实存在。 EF 和 Devart dotConnect 负责引号和语法。
  • 格特·阿诺德。我实际上使用的是except,但它创建了“Extent1”别名并在子查询中引用它。显然甲骨文不喜欢这样。正如我在帖子中所说,扁平化查询解决了许多其他查询中的这个问题。 (即通过将表关系从 WHERE 谓词向上移动到正文中来消除多级子查询)我会尝试 !Any() 看看它的行为是否有任何不同。
  • Gert Arnold !Any() 创建与 Except() 基本相同的查询

标签: entity-framework oracle11g many-to-many ora-00904


【解决方案1】:

您可以使用 EF 创建与问题中发布的基本相同的查询。我首先创建了一个具有以下属性的 poco 模型 EmployeePrivilege:int PrivilegeID 和 int EmployeeID。我没有将它添加到 DbContext。

var EmpPrivQuery = ctx.Privileges
                       .Where(p => p.PrivilegeName == "P3")
                       .SelectMany(p => p.Employees, (p, e) => new EmployeePrivilege{EmployeeID = e.EmployeeID, PrivilegeID = p.PrivilegeID}
                       .Distinct();

var employeesMissingPrivilege = from e in Employees
                                join epq in EmpPrivQuery
                                on e.EmployeeID equals epq.EmployeeID
                                into jointable
                                where jointable.Count()==0
                                select e;

我刚刚意识到您也可以在不创建 poco EmployeePrivilege 的情况下获得相同的结果,如下所示:

var EmpPrivQuery = ctx.Privileges
                        .Where(p => p.PrivilegeName == "P3")
                        .SelectMany(p => p.Employees.Select(e => e.EmployeeID)
                        .Distinct();

var employeesMissingPrivilege = from e in Employees
                                join epq in EmpPrivQuery
                                on e.EmployeeID equals epq
                                into jointable
                                where jointable.Count()==0
                                select e;

这两个 EF 查询都返回员工缺少针对 Sql Server 和 Oracle 的指定权限(使用 Devart 的 dotConnect for Oracle)。

我阅读的许多帖子都提到使用DefaultIfEmpty() 来实现左外连接。上面的查询有效,但是,如果有更好的方法使用DefaultIfEmpty(),请发布此结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-27
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 2016-07-24
    • 2023-03-06
    • 1970-01-01
    • 2021-09-22
    相关资源
    最近更新 更多