在Linq中使用Join和在ANSI连接语法之前使用"Olde Style"有什么区别?

Cal*_*nus 6 linq entity-framework

这个问题从我昨天问到的一个问题开始,这个问题为什么在我的实体上使用连接查询会产生极其复杂的SQL.似乎执行这样的查询:

        var query = from ev in genesisContext.Events
                    join pe in genesisContext.People_Event_Link
                    on ev equals pe.Event
                    where pe.P_ID == key
                    select ev;
Run Code Online (Sandbox Code Playgroud)

产生了在数据库上运行需要18秒的可怕SQL,而通过where子句(有点像ANSI SQL之前的语法)加入实体只需不到一秒的时间来运行并产生相同的结果

        var query = from pe in genesisContext.People_Event_Link
                    from ev in genesisContext.Events
                    where pe.P_ID == key && pe.Event == ev
                    select ev;
Run Code Online (Sandbox Code Playgroud)

我已经google了一遍,但仍然不明白为什么第二个产生不同的SQL到第一个.有人可以向我解释一下这个区别吗?我什么时候应该使用join关键字


这是我在查询中使用Join并运行18秒时生成的SQL:

SELECT 
1 AS [C1], 
[Extent1].[E_ID] AS [E_ID], 
[Extent1].[E_START_DATE] AS [E_START_DATE], 
[Extent1].[E_END_DATE] AS [E_END_DATE], 
[Extent1].[E_COMMENTS] AS [E_COMMENTS], 
[Extent1].[E_DATE_ADDED] AS [E_DATE_ADDED], 
[Extent1].[E_RECORDED_BY] AS [E_RECORDED_BY], 
[Extent1].[E_DATE_UPDATED] AS [E_DATE_UPDATED], 
[Extent1].[E_UPDATED_BY] AS [E_UPDATED_BY], 
[Extent1].[ET_ID] AS [ET_ID], 
[Extent1].[L_ID] AS [L_ID]
FROM  [dbo].[Events] AS [Extent1]
INNER JOIN [dbo].[People_Event_Link] AS [Extent2] ON  EXISTS (SELECT 
    1 AS [C1]
    FROM    ( SELECT 1 AS X ) AS [SingleRowTable1]
    LEFT OUTER JOIN  (SELECT 
            [Extent3].[E_ID] AS [E_ID]
        FROM [dbo].[Events] AS [Extent3]
        WHERE [Extent2].[E_ID] = [Extent3].[E_ID] ) AS [Project1] ON 1 = 1
    LEFT OUTER JOIN  (SELECT 
        [Extent4].[E_ID] AS [E_ID]
        FROM [dbo].[Events] AS [Extent4]
        WHERE [Extent2].[E_ID] = [Extent4].[E_ID] ) AS [Project2] ON 1 = 1
    WHERE ([Extent1].[E_ID] = [Project1].[E_ID]) OR (([Extent1].[E_ID] IS NULL) AND ([Project2].[E_ID] IS NULL))
)
WHERE [Extent2].[P_ID] = 291
Run Code Online (Sandbox Code Playgroud)

这是使用ANSI样式语法生成的SQL(如果我自己编写SQL,则与我要编写的内容非常接近):

SELECT * FROM Events AS E INNER JOIN People_Event_Link AS PE ON E.E_ID=PE.E_ID INNER JOIN PEOPLE AS P ON P.P_ID=PE.P_ID
WHERE P.P_ID = 291
Run Code Online (Sandbox Code Playgroud)

Cra*_*ntz 4

上述两个查询都不完全“正确”。在 EF 中,使用关系属性代替上述任一属性通常是正确的。例如,如果您的 Person 对象在名为 Person.PhoneNumbers 的属性中与 PhoneNumbers 具有一对多关系,则可以编写:

var q = from p in Context.Person
        from pn in p.PhoneNumbers
        select pn;
Run Code Online (Sandbox Code Playgroud)

EF 将为您构建联接。

就上面的问题而言,生成的 SQL 不同的原因是因为表达式树不同,即使它们产生相同的结果。表达式树映射到 SQL,您当然知道可以编写不同的 SQL,它们产生相同的结果但具有不同的性能。该映射旨在在您编写极其“传统”的 EF 查询时生成合适的 SQL。

但映射并没有智能到可以采用非常规查询并对其进行优化。在第一个查询中,您声明对象必须是等效的。在第二个中,您声明ID 属性必须是等效的。我上面的示例查询说“只需获取这一记录的详细信息。” EF 的设计主要是为了按照我展示的方式工作,但也可以很好地处理标量等效性。