如何使用Eager Loading
替换Lazy loading
?
让我们这样说。我有很多Include keys
以下的EF查询。性能明智非常慢。
那么如何使用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();
如果你能给我一个示例代码说明,那就完美了。
答案 0 :(得分:2)
使用EF 4.1及更高版本,您只需确保将代码优先导航属性(链接到其他实体的属性)定义为virtual
。然后,如果您在DbContext
内,则只有在实际使用(延迟加载)数据库时才会查询链接实体。
但是,如果您想立即获取所有数据,则会使用急切加载。通常有很好的理由。所以,我首先要说的是,如果你不知道为什么你急于加载,那么就不要这样做。确保链接实体的属性是虚拟的,然后删除查询中的.Include
语句。
但是,如果您正在查询DbContext
以外的数据,或者您立即使用数据,则在操作期间将数据提取到内存中是有意义的。
因此,在回答您的问题时,并不总是只需用eager
加载替换lazy
加载。您必须查看查询后对数据执行的操作,并了解如何仅返回所需的最小数据集。
添加了示例:
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
}
}
}
答案 1 :(得分:2)
如果您不使用预先加载(Include
调用),如果您正确设置了所有内容,将自动使用延迟加载:
virtual
导航属性延迟加载仅在您访问导航属性时才执行查询以加载相关实体,因此它可以提高性能,例如,如果您不需要所有相关数据,但如果您需要它们总是会导致更糟糕的情况由于大量数据库往返而导致的性能。