繁体   English   中英

C# 实体框架中的 SQL 请求取决于延迟加载或急切加载

[英]SQL requests in C# Entity Framework depending on lazy or eager loading

我有一个简单的连接查询,连接两个表(一个类别有很多产品):

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 ?

...当我使用.ToList() (渴望加载)
...当我使用(默认)延迟加载时

你混淆了两个不同的概念。 使用ToList()预加载不同,延迟加载则相反。 它是强制执行,与之对应的是延迟执行

因此,是否使用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; }
}

通常,急切加载优于延迟加载,因为它对数据库来说不那么“健谈”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM