3

我有一个用于搜索的通用基础存储库方法(为清楚起见进行了修剪):

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);

从这两个调用中,我试图创建一个利用相关实体的属性值的视图模型。为什么它会在一种情况下加载它们而不是另一种?这是同一个实体 TimeDetail,同一个基础存储库类?

您在调试器中看到的图像。为什么会加载一些相关实体(如 Facility 和 TimeDetailStatus)而其他不加载(如 OrderHeader 或 Customer) 在此处输入图像描述

更新

我查看了正在生成的查询,它们看起来都很相似,即它们没有加入其他表......所以上下文是否可能已经包含来自某些相关实体的一些缓存行,它们就是这样被包括在内?

4

1 回答 1

4

除非您使用集合上的方法,否则 EF 将执行延迟加载.Include()。由于您不这样做,因此您不会立即获得它们,但是当您调用它们时,您会懒惰地加载它们。

但是,这仅在对象上下文仍处于打开状态时才有效。如果上下文消失了,那么您连接到数据库的能力就消失了,因此您的属性将全部为空。

我的猜测是,您所看到的差异与您如何保持上下文有关。很难说,因为你没有显示你的上下文在哪里,但我会从那里开始。

编辑

不确定这是否与您的问题有关,但我只是想澄清延迟加载的内容。这是我最喜欢的 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填充变量。bookAuthors表从未在数据库中被触及。
  • 在第 7 行之后,上下文被释放,这意味着数据访问已死。
  • 第 11 行抛出试图访问该Author属性的异常。

但是,如果您使用调试器并在第 7 行停止,只是为了片刻查看 book 变量,它将立即查询Authors数据库中的表(当您在调试器中时),并Author在那个物体。这就是我所说的延迟加载的意思——当你实际访问该属性时,即使在调试器中,当上下文处于活动状态时,它会进行一个新的数据库调用。您现在可以继续代码,第 11 行就可以了,并且会打印作者姓名。

所以基本上,当涉及到 EF 时,不要相信调试器。即使看起来不像,它也会延迟加载数据。要弄清楚发生了什么,最好的办法是启动 SQL Profiler 并查看正在运行的查询。

于 2013-04-17T22:10:27.403 回答