【问题标题】:Entity framework doesn't use JOIN in SQL queries实体框架不在 SQL 查询中使用 JOIN
【发布时间】:2015-06-21 06:15:17
【问题描述】:

我为从Defect 实例获取Invoice 实例的一对多关系编写了一些代码。

mydbEntities ef = new mydbEntities (); //mydbEntities is derived from DbContext
ef.Database.Log = s => System.Diagnostics.Debug.WriteLine (s);
Invoice inv = ef.Defects.Where (i => i.Id == 5).SingleOrDefault ().Invoice;

这是EDM图的一部分:

我很好奇为什么它没有调用 INNER JOIN,而是执行了 2 个 SQL 查询。在我现在正在阅读的书中(“掌握实体框架”)中,在相同的情况下调用了 INNER JOIN。

调试输出:

SELECT TOP (2) 
    [Extent1].[Id] AS [Id], 
    [Extent1].[PositionId] AS [PositionId], 
    [Extent1].[InvoiceId] AS [InvoiceId], 
    [Extent1].[Count] AS [Count], 
    [Extent1].[Reason] AS [Reason]
    FROM [dbo].[Defect] AS [Extent1]
    WHERE 5 = [Extent1].[Id]


-- Executing at 6/21/2015 11:21:02 AM +05:00

-- Completed in 1 ms with result: SqlDataReader



Closed connection at 6/21/2015 11:21:02 AM +05:00

Opened connection at 6/21/2015 11:21:02 AM +05:00

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Number] AS [Number], 
    [Extent1].[InvoiceDate] AS [InvoiceDate]
    FROM [dbo].[Invoice] AS [Extent1]
    WHERE [Extent1].[Id] = @EntityKeyValue1


-- EntityKeyValue1: '1' (Type = Int32, IsNullable = false)

-- Executing at 6/21/2015 11:21:02 AM +05:00

-- Completed in 0 ms with result: SqlDataReader



Closed connection at 6/21/2015 11:21:02 AM +05:00

还有一个问题:使用 INNER JOIN 对 1 进行 2 次查询如何影响具有大型数据库的高负载应用程序的性能。

【问题讨论】:

  • 关于性能:我是一个极端的例子,两个表都包含一百万行,但内部连接它们会产生十行。在单独的查询中,您将拖动超过 200 万行并将它们加入您的应用程序中。使用内部联接,联接工作正在数据库上进行,您只需拖动超过 10 行。对于少数行,这两种方式可能都没有区别。基本上这是一个扩展风险。它今天有效,但可能在 3 年内无效。

标签: c# sql entity-framework inner-join ado.net-entity-data-model


【解决方案1】:

EntityFramework(和大多数其他 Linq to Sql 工具)只在一定程度上是懒惰的。有一组方法可以强制查询运行。一些例子是:

  • Single/SingleOrDefault
  • First/FirstOrDefault
  • ToList
  • ToArray

我使用的技巧是这些方法中的每一个都有一个返回Task<T> 的异步版本。因此,如果 IDE 中的自动完成功能包含 SingleOrDefaultAsync,那么很明显 SingleOrDefault 会导致查询运行。

请注意,Linq to Objects 也会发生相同的行为;每个 ToList、Single 等都是 eager 方法,而返回 IEnumerable 的方法是 lazy 并在第一次急切操作时执行。

为了回答您的问题,Include 方法通过返回连接数据来解决此问题。如果您正确使用它,这将提高性能。

在您的示例中,您从对象中获取Invoice 属性,因此正确的调用是使用.Include(d => d.Invoice).Include("Invoice")。这两个都告诉 EF 在第一个查询中撤回 Invoice 信息。

【讨论】:

  • 谢谢@Bringer128。在以下情况下使用 Include 是否正确?
【解决方案2】:

您应该添加 .Include(d => d.Invoice) 调用。试试这个:

    mydbEntities ef = new mydbEntities (); //mydbEntities is derived from DbContext
    ef.Database.Log = s => System.Diagnostics.Debug.WriteLine (s);
    Invoice inv = ef.Defects
        .Include(d => d.Invoice)
        .Where (i => i.Id == 5)
        .SingleOrDefault()
        .Invoice;

【讨论】:

  • 小心 - 你可以在这里得到 NullReferenceException:.SingleOrDefault().Invoice;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-06
  • 2017-08-15
  • 1970-01-01
相关资源
最近更新 更多