使用UnitOfWork到Service模式的EntityFramework

时间:2013-09-17 12:47:40

标签: c# entity-framework

我的申请表中有以下图层。

  1. Repository.Ef(这处理ef的上下文)
  2. 实体(此处为ef的所有实体)
  3. 核心(此层处理所有业务并且像包装器一样工作 在Ef<>之间桂)
  4. Gui(这是用户界面)
  5. 我有大多数类的接口并使用DI,但是这个版本被压缩为仅显示类。

    这是UnitOfWork,它将DbContext保存在我的Repository.Ef层中。

    public class UnitOfWork : DbContext, IUnitOfWork
        {
            static UnitOfWork()
            {
                Database.SetInitializer<UnitOfWork>(null);
            }
    
            public UnitOfWork()
                : base("Name=SalesDb") 
            {
            }
    
            public IRepository<T> Repository<T>() where T : EntityBase
            {
                return new Repository<T>(Set<T>());
            }
    
            public void ApplyStateChanges()
            {
                foreach (var dbEntityEntry in ChangeTracker.Entries())
                {
                    var entityState = dbEntityEntry.Entity as EntityBase;
                    if (entityState == null)
                        throw new InvalidCastException("All entites must implement the IObjectState interface, " +
                                                       "this interface must be implemented so each entites state can explicitely determined when updating graphs.");
    
                    dbEntityEntry.State = StateHelper.ConvertState(entityState.State);
                }
            }
    
            #region DBSET
    
        // HERE IS ALL MY DBSETS
    
            #endregion
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
            }
    
            public override int SaveChanges()
            {
                ApplyStateChanges();
                return base.SaveChanges();
            }
        }
    

    这是我的存储库(与UnitOfWork相同的层)

        public class Repository<T> : IRepository<T> where T : class, IEntity
    {
        private readonly DbSet<T> _dbSet;
    
        public Repository(DbSet<T> dbSet)
        {
            _dbSet = dbSet;
        }
    
        public IQueryable<T> Query()
        {
            var data = _dbSet.AsQueryable();
            return data;
        }
    
        public IEnumerable<T> GetAll()
        {
            return _dbSet;
        }
    
        public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
        {
            return _dbSet.Where(predicate);
        }
    
        public T FindById(int id)
        {
            return _dbSet.Find(id);
        }
    
        public void Add(T entity)
        {
            entity.State = ObjectState.Added;
            _dbSet.Add(entity);
        }
    
        public void Remove(T entity)
        {
            entity.State = ObjectState.Deleted;
            _dbSet.Remove(entity);
        }
    
        public void Update(T entity)
        {
            entity.State = ObjectState.Modified;
            _dbSet.Attach(entity);
        }
    }
    

    这是我的核心层(业务规则和GUI层之间的包装) 以下是我的ServiceUnit。

      public class ServiceUnit
    {
        internal readonly IUnitOfWork unitOfWork;
    
        public ServiceUnit()
        {
            unitOfWork = new UnitOfWork();
        }
    
        public void Add<T>(T entity, int marketId, string username) where T : EntityBase
        {
            entity.MarketId = marketId;
            entity.ChUser = username;
            entity.ChTime = DateTime.Now;
            entity.Deleted = false;
    
            unitOfWork.Repository<T>().Add(entity);
            unitOfWork.SaveChanges();
        }
    
        public void Update<T>(T entity, string username) where T : EntityBase
        {
            entity.ChUser = username;
            entity.ChTime = DateTime.Now;
    
            unitOfWork.Repository<T>().Update(entity);
            unitOfWork.SaveChanges();
        }
    
        public void Remove<T>(int id) where T : EntityBase
        {
            var entity = unitOfWork.Repository<T>().FindById(id);
            entity.Deleted = true;
            entity.ChTime = DateTime.Now;
    
            unitOfWork.Repository<T>().Update(entity);
            unitOfWork.SaveChanges();
        }
    
        public IEnumerable<T> Find<T>(int? marketId = null, Expression<Func<T, bool>> predicate = null) where T : EntityBase
        {
            var data = unitOfWork.Repository<T>()
                .Find(predicate);
    
            if (marketId != null)
            {
                data = data
                    .Where(t => t.MarketId == marketId);
            }
    
            return data;
        }
    
        public T FindById<T>(int id) where T : EntityBase
        {
            return unitOfWork.Repository<T>().FindById(id);
        }
    
        public void Commit()
        {
            unitOfWork.SaveChanges();
        }
    
    }
    

    这是一个处理所有联系人功能的服务类

        public class ContactService
    {
        private readonly ServiceUnit serviceUnit;
    
        private IRepository<Contact> contactRep
        {
            get { return serviceUnit.unitOfWork.Repository<Contact>(); }
        }
    
        private IRepository<ContactUserProfile> contactUserProfileRep
        {
            get { return serviceUnit.unitOfWork.Repository<ContactUserProfile>(); }
        }
    
        public ContactService(ServiceUnit serviceUnit)
        {
            this.serviceUnit = serviceUnit;
        }
    
        public IEnumerable<ContactUserProfile> GetContactsForUser(int marketId, int userId, int status)
        {
            return contactUserProfileRep
                .Query()
                .Where(u => u.Contact.MarketId == marketId)
                .Where(cup => cup.UserProfileId == userId)
                .Where(c => c.Deleted == false)
                .Where(c => c.Contact.Status == status)
                .ToList();
        }
    }
    

    让我们解释一下我如何使用所有这些代码。 首先,我不希望在我的gui层中依赖实体框架,并且使用此服务包装器(ServiceUnit),我不必引用实体框架。

    每个页面请求都创建一个ServiceUnit,ServiceUnit创建一个新的UnitOfWork来保存整个EntityFramework上下文。

    例如,联系页面创建ServiceUnit和ServiceContact并注入服务单元,因此我对请求具有相同的上下文。

    这种模式会导致任何问题吗?如果我在这里遗漏了一些重要的东西,我只想这样做。

1 个答案:

答案 0 :(得分:2)

您需要“ServiceUnit”课吗?为什么不直接在服务中使用UnitOfWork?

我建议基本上有四个项目:

  • 数据访问层项目:EF DbContext,存储库,UnitOfWork。参考“实体”项目。

  • 实体项目:EF实体(如果您想共享EF实体) 整个解决方案)。不参考任何其他项目。

  • 服务层项目:ContactService等。每个都有UnitOfWork 注入他们。引用“数据访问层”和“实体”项目。

  • GUI项目:使用您的UI。引用“实体”和“服务层”项目。

我认为ServiceUnit是一个不必要的抽象,服务可以直接处理UnitOfWork(除非我遗漏了什么)。

顺便说一句,我不建议从您的存储库中公开IQueryable(正如有人在另一个问题上向我建议的那样)。暴露它之后,查询将在您的存储库外部执行,因此您无法控制其执行(异常处理等)。如果你搜索一下,你会发现有一些争议。