使用 dbcontext 和 projection 进行预加载
eager loading with dbcontext and projection
我们正在将项目从 ObjectContext 转换为 dbContext。
我们当前的问题是处理预加载的方式不同。
示例上下文
public class Person
{
public virtual ICollection<Email> Emails { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Email
{
public string Address{ get; set; }
}
public class Post
{
public string Content{ get; set; }
}
我们在整个企业中有许多代码段期望加载电子邮件,因此调用 person.Emails.First()
时没有考虑它。
所以我们需要确保 Emails
被热切加载。
有时候我们就可以 Include
然而,当我们在数据层中使用投影时,我们 运行 遇到了问题。即
return context.Persons.Select(p=> new Top5VM {
Person = p,
TopPosts = p.Posts.Take(5)
};
我们有很多代码依赖于 Top5VM
并期望加载 Person.Emails
。
无论我们尝试过什么,我们都无法弄清楚将 Include
(或 Load
)函数调用放在哪里才能真正发挥作用。
有了 ObjectContext,我们将在 Top5VM
上有一个虚拟 属性,称为 Emails
。一旦它被加载,ObjectContext 就会引用所有这些 Entities
,因此即使我们通过 person 对象访问它们也不需要返回到服务器。但这不再适用于 DbContext
想通了。我需要设置 context.Configuration.LazyLoadingEnabled = false;
任何时候我想使用投影来完成预先加载。当然,除非我想直接从投影访问加载的实体。
您可以始终使用自己的 DbContext
来做到这一点:
public class MyDbContext : DbContext
{
public MyDbContext() : base()
{
Configuration.LazyLoadingEnabled = false;
}
}
然后到处使用它而不是 DbContext
。
或者,如果您控制了所有 POCO,则可以从相关集合中删除 virtual
关键字……virtual
关键字是 Microsoft 用于延迟加载的神奇连接.
编辑
我也倾向于将此作为扩展方法:
static class DbContextExtensions
{
public static DbContext AsEagerLoadingContext(this IDbContext context)
{
context.Configuration.LazyLoadingEnabled = false;
//context.Configuration.AutoDetectChangesEnabled = false;
return context;
}
}
如此使用,允许根据需要使用或不使用延迟加载:
using (var context = new DbContext().AsEagerLoadingContext())
context.Stuff.Select(s => s.AllTheThings);
我们正在将项目从 ObjectContext 转换为 dbContext。 我们当前的问题是处理预加载的方式不同。
示例上下文
public class Person
{
public virtual ICollection<Email> Emails { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Email
{
public string Address{ get; set; }
}
public class Post
{
public string Content{ get; set; }
}
我们在整个企业中有许多代码段期望加载电子邮件,因此调用 person.Emails.First()
时没有考虑它。
所以我们需要确保 Emails
被热切加载。
有时候我们就可以 Include
然而,当我们在数据层中使用投影时,我们 运行 遇到了问题。即
return context.Persons.Select(p=> new Top5VM {
Person = p,
TopPosts = p.Posts.Take(5)
};
我们有很多代码依赖于 Top5VM
并期望加载 Person.Emails
。
无论我们尝试过什么,我们都无法弄清楚将 Include
(或 Load
)函数调用放在哪里才能真正发挥作用。
有了 ObjectContext,我们将在 Top5VM
上有一个虚拟 属性,称为 Emails
。一旦它被加载,ObjectContext 就会引用所有这些 Entities
,因此即使我们通过 person 对象访问它们也不需要返回到服务器。但这不再适用于 DbContext
想通了。我需要设置 context.Configuration.LazyLoadingEnabled = false;
任何时候我想使用投影来完成预先加载。当然,除非我想直接从投影访问加载的实体。
您可以始终使用自己的 DbContext
来做到这一点:
public class MyDbContext : DbContext
{
public MyDbContext() : base()
{
Configuration.LazyLoadingEnabled = false;
}
}
然后到处使用它而不是 DbContext
。
或者,如果您控制了所有 POCO,则可以从相关集合中删除 virtual
关键字……virtual
关键字是 Microsoft 用于延迟加载的神奇连接.
编辑
我也倾向于将此作为扩展方法:
static class DbContextExtensions
{
public static DbContext AsEagerLoadingContext(this IDbContext context)
{
context.Configuration.LazyLoadingEnabled = false;
//context.Configuration.AutoDetectChangesEnabled = false;
return context;
}
}
如此使用,允许根据需要使用或不使用延迟加载:
using (var context = new DbContext().AsEagerLoadingContext())
context.Stuff.Select(s => s.AllTheThings);