玩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
我确定我错过了一些东西,但我不知道是什么,或者是真正的急切加载行为?
答案 0 :(得分:1)
这是正常的。在您的简单情况下(1包含),您会看到EF将实际查询作为子查询,然后选择它并应用排序。
如果您尝试在单个查询中包含更多包含,您将看到行为更改,因为它将开始为每个实体执行单个查询,然后将所有查询“联合”,最后选择结果。< / p>
根据我的经验,急切加载EF导致几乎总是在性能下降,所以我建议避免它,除非你有特定需求,并且你已经深刻考虑了性能影响。
答案 1 :(得分:0)
使用Include
,您说您希望一个数据库匹配,从而产生多个对象。
为了做到这一点,EF必须构建一个合适的查询和进一步处理结果。假设我们有一个表A
,每个A
都有很多B
个。特别是,有两个A
,每个都有三个(不同的)B
s。假设我们要求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
个对象,并相应地填充每个A
的{{1}}集合。
这就是你渴望加载的要求 - 你想要更少的数据库调用,但每个数据库返回的数据更多。
此外:B
列是(我猜)是一个指标列,用于说明特定C1
是否有A
s;而B
是因为您要求TOP (2)
,因此它必须能够区分现有的1条记录和1条以上的记录。