1

在玩 EF5 时,我发现了一些奇怪的东西。给定这两个类和一个简单的查询

public class Customer {
  public string Name { get; set; }
  public string Email { get; set; }
  ...
  public virtual IList<Order> Orders { get; set; }
} 

public class Order {
  public Customer Cust { get; set; }
  public Datetime DateOrdered { get; set; }
  ...
}

using (var ctx = new DatabaseContext(connstring))
{
 Customer c= ctx.customers.Include(x => x.orders).Where(x => x.Id == 1).Single<Customer>();

 foreach (Order o in c.orders)
 {
   Console.WriteLine(o.ToString());
 }
}

我检查了 SQL Server Profiler 输出,我认为查询是不必要的复杂:

SELECT 
[Project1].[Id] AS [Id], 
[Project1].[name] AS [name], 
[Project1].[C1] AS [C1], 
[Project1].[Id1] AS [Id1], 
[Project1].[customer_Id] AS [customer_Id], 
[Project1].[timeordered] AS [timeordered]
FROM ( SELECT 
    [Limit1].[Id] AS [Id], 
    [Limit1].[name] AS [name], 
    [Extent2].[Id] AS [Id1], 
    [Extent2].[customer_Id] AS [customer_Id], 
    [Extent2].[timeordered] AS [timeordered], 
    CASE WHEN ([Extent2].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
    FROM   (SELECT TOP (2) [Extent1].[Id] AS [Id], [Extent1].[name] AS [name]
        FROM [dbo].[Customers] AS [Extent1]
        WHERE 1 = [Extent1].[Id] ) AS [Limit1]
    LEFT OUTER JOIN [dbo].[Orders] AS [Extent2] ON [Limit1].[Id] = [Extent2].[customer_Id]
)  AS [Project1]
ORDER BY [Project1].[Id] ASC, [Project1].[C1] ASC

我确定我错过了一些东西,但我不知道是什么,或者这是急切加载的正常行为?

4

2 回答 2

1

这很正常。在您的简单情况(1 包括)中,您看到 EF 将实际查询作为子查询进行,然后它选择它并应用排序。

如果您尝试在单个查询中包含更多包含,您将看到行为发生变化,因为它将开始对每个实体执行单个查询,然后将所有查询“联合”在一起,最后选择结果。

根据我的经验,在 EF 中急切加载几乎总是会导致性能下降,因此我建议您避免使用它,除非您有特定需求并且您已经深入考虑了性能影响。

于 2013-08-08T12:43:38.537 回答
0

通过使用Include,您是在说您希望一个数据库命中产生许多对象。

为此,EF 必须构造一个合适的查询并对结果进行进一步处理。假设我们有一张桌子A,每张桌子A都有很多Bs。特别是,有两个As,每个都有三个(不同的)Bs。假设我们要求A.Include("B"). EF 构造一个查询,其结果集基本上如下所示:

AId    AProp1    AProp2     BId    BAId   BProp1   BProp2
1      xxx       yyy        56     1      aaa      bbb
1      xxx       yyy        57     1      ccc      ddd
1      xxx       yyy        58     1      eee      fff
2      www       zzz        101    2      ggg      ggg
2      www       zzz        102    2      jjj      kkk
2      www       zzz        103    2      mmm      nnn

然后,EF 使用此数据构造两个A对象、六个B对象,并适当地填充每个对象AB集合。

这就是您通过急切加载所要求的 - 您希望更少的数据库调用,但每个返回的数据更多。

另外:该C1列(我猜)是一个指示列,用于说明某个特定项是否A具有Bs;那TOP (2)是因为你要求Single,所以它必须能够区分存在 1 条和多条记录。

于 2013-08-08T12:55:17.913 回答