【问题标题】:Replace Eager Loading by using Lazy loading使用延迟加载替换急切加载
【发布时间】:2013-01-20 19:29:01
【问题描述】:

如何使用Lazy loading替换Eager Loading

可以这样说。我有以下类型的 EF 查询,其中有很多 Include keys 。性能方面这非常慢

那么如何使用Lazy loading 提高以下代码的性能?

from owner in Catalog.Owners
            where owner.Key == ownerKey
            from invoice in owner.Invoices
            where invoice.Provider.Key == providerKey
            where invoice.Id == id
            select invoice)
            .Include(i => i.Owner.Credits)
            .Include(i => i.Provider)
            .Include(i => i.Items.Select(s => s.Allocation.Service))
            .Include(i => i.Items.Select(s => s.Allocation.Pet))
            .FirstOrDefault();

如果您能给我一个示例代码说明,那就完美了。

【问题讨论】:

    标签: .net performance entity-framework c#-4.0 entity-framework-4.1


    【解决方案1】:

    使用 EF 4.1 及更高版本,您只需确保将代码优先导航属性(链接到其他实体的属性)定义为 virtual。那么,如果你在一个DbContext里面,链接的实体只会在实际使用(延迟加载)时从数据库中查询。

    但是,当您需要立即获取所有数据时,会使用预加载。这通常有充分的理由。因此,我首先要说的是,如果您不知道为什么要急切加载,那就不要这样做。确保链接实体的属性是虚拟的,然后删除查询中的 .Include 语句。

    但是,如果您在 DbContext 之外获取要查询的数据,或者您立即使用这些数据,则在操作期间将该数据拉入内存是有意义的。

    因此,在回答您的问题时,并不总是将 eager loading 替换为 lazy loading。查询数据后,您必须查看对数据的处理情况,并了解如何仅返回您需要的最小集合。

    添加示例:

        public class Person
        {
            public int Id { get; set; }
            public string Name { get; set; }
    
            public virtual ICollection<Car> Cars { get; set; } //make it virtual
    
        }
    
        public class Car
        {
            public int Id { get; set; }
            public string Make { get; set; }
            public string Model { get; set; }
        }
    
        public class MyContext : DbContext
        {
            public IDbSet<Person> People { get; set; }
            public IDbSet<Car> Cars { get; set; }
        }
    
        class Program
        {
            private static void Main(string[] args)
            {
                using (var context = new MyContext())
                {
                    var person = context.People.FirstOrDefault(p => p.Id == 1); // calls the database
    
                    var car = person.Cars.FirstOrDefault(c => c.Id == 2); // Lazy loads Cars
    
                }
            }
        }
    

    【讨论】:

    • 你能举个简单的例子来说明如何做延迟加载吗?
    • @Sampath 我添加了一个示例。如您所见,Cars 导航属性是虚拟的。这允许 EF 在需要时延迟加载它。
    • 但请注意延迟加载可能会导致 N+1 问题
    【解决方案2】:

    如果您不使用急切加载(Include 调用),如果您已正确设置所有内容,则会自动使用延迟加载:

    • virtual导航属性
    • 允许延迟加载和创建代理(应该默认)
    • 在用于加载根对象的对象上下文范围内执行延迟加载

    延迟加载仅在您访问导航属性时执行查询以加载相关实体,因此它可以提高性能,例如,如果您并不总是需要所有相关数据,但如果您总是需要它们,则可能会导致更糟大量数据库往返带来的性能。

    【讨论】:

    • 你能举个简单的例子来说明如何做延迟加载吗?
    • var owner = invoice.Owner; - 如果您没有加载所有者并且延迟加载正在工作,EF 将在调用此代码时加载它。
    猜你喜欢
    • 1970-01-01
    • 2015-09-30
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多