EF 6:无法生成我想要的查询,是否应该使用Native SQL?

时间:2014-04-03 11:00:57

标签: c# sql-server linq entity-framework many-to-many

我有以下两个具有多对多映射的实体:

ConferenceRoom {ID, Name, IsAccessibleGlobally}  <--- Many-To-Many ---> Department {ID, Name}
  • 任何部门都有许多可供部门员工使用的会议室。
  • 可能会有多个部门的员工访问会议室,因为部门可能有子部门。即任何部门也可以访问其子部门的会议室。
  • 会议室也可以全局访问,在这种情况下,标志IsAccessibleGlobally设置为true,并且表中不存在将其映射到特定部门的记录,这些记录将由多对多关系产生。

知道DepartmentConferenceRoom之间由多对多关系产生的表格被称为DeptCRMapping,如果我们有一个等于7的给定部门ID,例如,其员工可以访问的会议室将是DeptCRMapping在全球可访问的会议室中配置的会议室。

我为这样的要求编写的SQL查询如下:

SELECT CR.ID, CR.Name
 FROM ConferenceRoom CR
 LEFT JOIN DeptCRMapping DCRM ON CR.ID = DCRM.IDConferenceRoom
 WHERE DCRM.IdDepartment = 7
 OR    CR.IsAccessibleGlobally = 1

以下是我的POCO课程:

public class Department
{
    public long Id { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<ConferenceRoom> ConferenceRooms { get; set; }
}

public class ConferenceRoom
{
    public long Id { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<Department> Departments { get; set; }
}

我无法弄清楚我应该编写的Linq-To-Entities查询来获取上面提到的SQL查询。这是我到目前为止所尝试的内容:

var left = ctx.ConferenceRooms;
var right = ctx.ConferenceRooms.Where(v => v.Departments.Any(d => d.Id == 7));
var query = from l in left
            from r in right
            where l.Id == r.Id || l.AccesGlobal
            select l;

生成的sql是:

SELECT 
    [Extent1].[ID] AS [ID], 
    [Extent1].[Nom] AS [Nom], 
    [Extent1].[AccesGlobal] AS [AccesGlobal]
    FROM  [dbo].[Verbalisateur] AS [Extent1]
    CROSS JOIN [dbo].[Verbalisateur] AS [Extent2]
    WHERE ( EXISTS (SELECT 
        1 AS [C1]
        FROM [dbo].[VerbalisateursJuridiction] AS [Extent3]
        WHERE ([Extent2].[ID] = [Extent3].[IdVerbalisateur]) AND (5 = [Extent3].[IdJuridiction])
    )) AND ([Extent1].[ID] = [Extent2].[ID] OR [Extent1].[AccesGlobal] = 1)

我可以做些什么来获得类似于我想要的查询。另外请注意,你们建议在使用ORM时使用本机SQL,至少是为了查询结果。谢谢。


修改

好吧,在找不到使用EF 6执行本机SQL查询的方法之后,我就去了:

ctx.ConferenceRooms.Where(cf => cf.IsAccessibleGlobally || cf.Departments.Any(d => d.Id == 7))

虽然生成的查询不是我所希望的,但至少代码是可读的。

3 个答案:

答案 0 :(得分:1)

通常当涉及到联接时,尤其是当您经常进行时,它应该是一个视图。这应该可以加快查询时间,并且它将明确定义查看数据的方式。我会尽可能地将您的原生SQL保存在您的数据库中。

答案 1 :(得分:0)

目前我没有办法测试它,但由于您的查询等同于以下内容(性能应该相似,在我看来,对于新手来说更容易理解):

SELECT 
    CR.ID, CR.Name
FROM ConferenceRoom CR
WHERE 
    CR.IsAccessibleGlobally = 1
UNION ALL
SELECT 
    CR.ID, CR.Name
FROM DeptCRMapping DCRM
INNER JOIN ConferenceRoom CR ON DCRM.IDConferenceRoom = CR.ID
WHERE 
    DCRM.IdDepartment = 7
    and CR.IsAccessibleGlobally = 0

您可以尝试以下LINQ查询(目前我无法测试生成的SQL),该查询应该提供与上述类似的查询:

var query =
    ctx.ConferenceRoom
        .Where(cr => cr.IsAccessibleGlobally == 1)
        .Select(cr => new { cr.ID, cr.Name })
        .Concat(
            ctx.Department
                .Where(d => d.Id == 7)
                .Select(d => 
                    d.ConferenceRooms
                    .Where(cr => cr.IsAccessibleGlobally == 0)
                    .Select(cr => new { cr.ID, cr.Name }))
        )

答案 2 :(得分:0)

你快到了那里:

var rooms = ctx.ConferenceRooms
               .Where(v => v.Departments.Any(d => d.Id == 7)
                        || v.AccesGlobal);