【问题标题】:SQL requests in C# Entity Framework depending on lazy or eager loadingC# Entity Framework 中的 SQL 请求取决于延迟加载或急切加载
【发布时间】: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?

【问题讨论】:

    标签: c# sql entity-framework lazy-loading eager-loading


    【解决方案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; }
    }
    

    但通常,急切加载比延迟加载更受欢迎,因为它对数据库来说不太“健谈”。

    【讨论】:

    • 非常感谢您的澄清。显然和我一起讲课的那个人并没有很好地区分这个概念,但幸运的是有像你这样的人:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-30
    • 1970-01-01
    • 2017-02-28
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    相关资源
    最近更新 更多