C# Entity Framework 中的 SQL 请求取决于延迟加载或急切加载
Posted
技术标签:
【中文标题】C# Entity Framework 中的 SQL 请求取决于延迟加载或急切加载【英文标题】:SQL requests in C# Entity Framework depending on lazy or eager loading 【发布时间】:2020-03-10 18:51:14 【问题描述】:我有一个简单的连接查询,连接两个表(一个类别有很多产品):
using (ProdContext db = new ProdContext())
var query = from category in db.Categories
join product in db.Products
on category.CategoryID equals product.CategoryID into productList
select new
categoryName = category.Name,
products = productList
;
foreach (var c in query)
Console.WriteLine("* 0", c.categoryName);
foreach (var p in c.products)
Console.WriteLine(" - 0", p.Name);
;
对于课程:
class Category
public int CategoryID get; set;
public String Name get; set;
public List<Product> Products get; set;
class Product
public int ProductID get; set;
public String Name get; set;
public int UnitsInStock get; set;
public int CategoryID get; set;
class ProdContext : DbContext
public DbSet<Category> Categories get; set;
public DbSet<Product> Products get; set;
通常一切都很好,但是当我开始尝试急切加载和延迟加载时,我感到很困惑,因为无论我是否在查询末尾添加.ToList()
,我的 SQL 请求总是如下所示:
SELECT
[Project1].[CategoryID] AS [CategoryID],
[Project1].[Name] AS [Name],
[Project1].[C1] AS [C1],
[Project1].[ProductID] AS [ProductID],
[Project1].[Name1] AS [Name1],
[Project1].[UnitsInStock] AS [UnitsInStock],
[Project1].[CategoryID1] AS [CategoryID1],
FROM
(SELECT
[Extent1].[CategoryID] AS [CategoryID],
[Extent1].[Name] AS [Name],
[Extent2].[ProductID] AS [ProductID],
[Extent2].[Name] AS [Name1],
[Extent2].[UnitsInStock] AS [UnitsInStock],
[Extent2].[CategoryID] AS [CategoryID1],
CASE WHEN ([Extent2].[ProductID] IS NULL)
THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM
[dbo].[Categories] AS [Extent1]
LEFT OUTER JOIN
[dbo].[Products] AS [Extent2] ON [Extent1].[CategoryID] = [Extent2].[CategoryID]) AS [Project1]
ORDER BY
[Project1].[CategoryID] ASC, [Project1].[C1] ASC
据我了解,当我使用.ToList()
(急切加载)时,它应该看起来像这样,但是当我使用(默认)延迟加载时,它应该发送许多 sql 请求,分别询问 foreach 循环的所有元素。我的问题是 - 为什么没有区别并且总是只发送一个 SQL?
【问题讨论】:
【参考方案1】:...当我使用
.ToList()
时(急切加载) ...当我使用(默认)延迟加载时
您混淆了两个不同的概念。使用ToList()
与eager loading 不同,lazy loading 则相反。它是强制执行,与延迟执行对应。
因此,使用或不使用ToList()
永远不会确定 LINQ 查询运行时 EF 将生成的 SQL 查询的数量。 Entity Framework 6(您的版本)总是尝试将 LINQ 查询转换为一个 SQL 语句。你有一个 LINQ 语句,因此你会得到一个 SQL 语句。
各种加载策略中的“加载”始终与填充导航属性有关。急切加载由Include
方法执行。例如:
var query =
from category in db.Categories
.Include(c => c.Products)
select category;
这会返回加载了 Products
导航属性的类别。
通过访问已执行的 LINQ 查询结果中的导航属性触发延迟加载。例如:
var query = db.Categories.ToList();
foreach (var c in query)
Console.WriteLine("* 0", c.categoryName);
foreach (var p in c.Products) // <= new query triggered here.
Console.WriteLine(" - 0", p.Name);
;
为了发生延迟加载,导航属性应定义为virtual
:
class Category
public int CategoryID get; set;
public String Name get; set;
public virtual ICollection<Product> Products get; set;
但通常,急切加载比延迟加载更受欢迎,因为它对数据库来说不太“健谈”。
【讨论】:
非常感谢您的澄清。显然和我一起讲课的那个人并没有很好地区分这个概念,但幸运的是有像你这样的人:)以上是关于C# Entity Framework 中的 SQL 请求取决于延迟加载或急切加载的主要内容,如果未能解决你的问题,请参考以下文章
使用带有 C# 的 Entity Framework 6 调用现有的存储过程
如何使用 Oracle 和 SQL Server 将 .NET 4.5 C# Entity Framework 6 中的列映射为大写?