使用存储库模式在实体框架中进行延迟加载

时间:2013-11-15 14:44:32

标签: c# entity-framework domain-driven-design lazy-loading repository-pattern

我有一个像:

这样的实体
public class Doctor : User
{
    public Doctor(string userName, string firstName, string lastName,
        string mobileNumber, string email, Sexes sex, Role myRole, DoctorExpertises expertise)
        : base(userName, firstName, lastName, mobileNumber, email, sex, myRole)
    {
        this.Expertise = expertise;
        this.Results = new List<Result>();
    }

    private Doctor()
    {
        this.Results = new List<Result>();
    }

    public void AddResult(Result result)
    {
        this.Results.Add(result);
    }

    public DoctorExpertises Expertise { get; private set; }

    private ICollection<Result> results;

    public virtual ICollection<Result> Results
    {
        get { return results; }
        private set { results = value; }
    }
}

我有典型的存储库,如:

    public abstract class RepositoryBase<T> where T : class
    {
        private DbContext dataContext;
        protected readonly IDbSet<T> dbset;

        protected RepositoryBase(IDatabaseFactory databaseFactory)
        {
            DatabaseFactory = databaseFactory;
            dbset = DataContext.Set<T>();
        }

        protected IDatabaseFactory DatabaseFactory
        {
            get;
            private set;
        }

        protected DbContext DataContext
        {
            get { return dataContext ?? (dataContext = DatabaseFactory.Get()); }
        }
        public virtual void Add(T entity)
        {
            dbset.Add(entity);
        }
        public virtual void Update(T entity)
        {
            dbset.Attach(entity);
            dataContext.Entry(entity).State = EntityState.Modified;
        }
        public virtual void Delete(T entity)
        {
            dbset.Remove(entity);
        }
        public virtual void Delete(Expression<Func<T, bool>> where)
        {
            IEnumerable<T> objects = dbset.Where<T>(where).AsEnumerable();
            foreach (T obj in objects)
                dbset.Remove(obj);
        }
        public virtual T GetById(long id)
        {
            return dbset.Find(id);
        }
        public virtual T GetById(string id)
        {
            return dbset.Find(id);
        }
        public virtual IEnumerable<T> GetAll()
        {
            return dbset.ToList();
        }
        public virtual IEnumerable<T> GetMany(Expression<Func<T, bool>> where)
        {
            return dbset.Where(where).ToList();
        }
        public T Get(Expression<Func<T, bool>> where)
        {
            return dbset.Where(where).FirstOrDefault<T>();
        }
}

我希望懒惰加载医生的一个结果,测试代码如下:

[TestMethod]
public void TestShouldLoadPropertyIfLazyLoaded()
{
    // Act
    Doctor doctor = this.userRepository.Get(u => u.UserName == "soroosh") as Doctor;
    Result result = doctor.Results.FirstOrDefault();

    // Asserts
    Assert.IsNotNull(doctor);
    Assert.IsNotNull(result);
}

不幸的是它没有正常工作医生不是null但是结果为空。

如果我使用include方法急切加载,它会正确加载,但我想明确使用延迟加载。

我已经看过this question和其他问题,但是没有这些问题没有用,因为所有这些问题都使用急切加载来解决问题。急切加载并不适合我们,因为在我的main problem中似乎无法加载。

我该怎么办?

2 个答案:

答案 0 :(得分:0)

我认为如果你完全定义你的聚合边界,你真的不需要担心这一点 - 你可以总是在加载实体时执行域操作时急切地加载,因为你的关系不应该交叉聚合边界。因此,您的存储库只能加载和保存给定类型的单个聚合,以便可以调用该聚合上的行为。

不要误解我的意思,你可能仍然想查询数据库以将数据放在UI等上,但你可以使用像Linq to SQL,Dapper等简单的工具并直接从数据库中删除数据进入用户界面,跳过所有ORM渴望/延迟加载废话。

答案 1 :(得分:0)

这应该可行,包括我在内的人每天都会这样做并且有效。我看到两个可能的罪魁祸首:

  • dbcontext工厂可能会创建一个禁用延迟加载的上下文
  • 您的Records属性的setter是私有的,生成的代理实体可能无法正确处理它。只需将其更改为公开。

检查两者,重点关注第二个。