我有一个用于搜索的通用基本存储库方法(为清楚起见进行了删减):
public class Repository<TRepository> : IRepository<TRepository>
where TRepository : class, IEntity, new()
{
public virtual IQueryable<TRepository> SearchFor(Expression<Func<TRepository, bool>> predicate, Expression<Func<TRepository, bool>> orderbylinq = null)
{
if (orderbylinq == null)
{
return DbSet.Where(predicate);
}
else
{
return DbSet.Where(predicate).OrderBy(orderbylinq);
}
}
}
我有一个派生的存储库类:
public class TimeDetailRepository : Repository<TimeDetail>
在我的服务层,我有一个调用 SearchFor 方法的类:
private TimeDetailRepository _timeDetailRepository;
public ManageTimeDetailsAppServ()
: base(new TimeDetailRepository())
{
_timeDetailRepository = new TimeDetailRepository();
}
IQueryable<TimeDetail> timeDetails2 = _timeDetailRepository.SearchFor(
x => x.Id == 3214);
在这种情况下,timeDetails2 已完全加载(已加载所有相关实体)。
但是,我有另一个类(一个基本服务层类)进行相同的 SearchFor 调用,但它不加载相关实体:
IQueryable<TRepository> dbEntity = _repository.SearchFor(x => x.Id == result.Value);
从这两个调用中,我试图创建一个 View 模型,它利用来自相关实体的属性值。为什么它会在一种情况下加载它们而不是另一种情况?这是相同的实体 TimeDetail,相同的基础存储库类?
您在调试器中看到的图像。为什么会加载一些相关实体(如 Facility 和 TimeDetailStatus)而其他实体不会(如 OrderHeader 或 Customer)
更新
我查看了正在生成的查询,它们看起来很相似,即它们没有连接到其他表...所以上下文是否可能已经包含一些来自一些相关实体的缓存行,这是他们如何被包容?
最佳答案
除非您在集合上使用 .Include()
方法,否则 EF 将进行延迟加载。由于您没有这样做,因此不会立即获取它们,但会在您调用它们时延迟加载它们。
但是,这仅在对象上下文仍处于打开状态时有效。如果上下文消失了,那么您连接到数据库的能力也就消失了,因此您的属性将全部为空。
我的猜测是,您看到的差异与您保持上下文的方式有关。很难说清楚,因为您没有显示上下文的位置,但我会从那里开始。
编辑
不确定这是否与您的问题有关,但我只是想澄清一下延迟加载的问题。这是我最喜欢的 EF 示例:2 个表:Author(AuthorId, AuthorName) 和 Book(BookId, AuthorId(FK), BookTitle)
/* 1 */ static void Main(string[] args)
/* 2 */ {
/* 3 */ Book book;
/* 4 */ using (var context = new SampleDbEntities())
/* 5 */ {
/* 6 */ book = context.Books.Single(b => b.BookId == 1);
/* 7 */ }
/* 8 */
/* 9 */ try
/* 10 */ {
/* 11 */ Console.WriteLine(book.Author.AuthorName);
/* 12 */ }
/* 13 */ catch (Exception ex)
/* 14 */ {
/* 15 */ Console.WriteLine(ex.Message);
/* 16 */ }
/* 17 */
/* 18 */ Console.ReadLine();
/* 19 */ }
如果您按原样运行此代码,将会发生以下情况:
- 第 6 行将仅查询
Books
表并用匹配的记录填充book
变量。Authors
表从未在数据库中被触及。 - 在第 7 行之后,上下文被释放,这意味着数据访问已死。
- 第 11 行抛出试图访问
Author
属性的异常。
但是,如果您使用调试器并在第 7 行停止,只是为了瞬间查看 book 变量,它会立即查询数据库中的 Authors
表(而您重新在调试器中),并填充该对象的 Author
属性。这就是我所说的延迟加载的意思 - 当您实际访问该属性时,即使在调试器中,当上下文处于事件状态时,它也会进行新的数据库调用。您现在可以继续代码,第 11 行就可以了,并且会打印作者姓名。
所以基本上,当谈到 EF 时,不要相信调试器。它延迟加载数据,即使它看起来不像。要弄清楚发生了什么,最好的办法是启动 SQL 事件探查器并查看运行了哪些查询。
关于entity-framework - EF - 为什么有时是急切加载,有时是延迟加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16070148/