代码之家  ›  专栏  ›  技术社区  ›  Nickso

工作单位与急负荷

  •  3
  • Nickso  · 技术社区  · 6 年前

    我知道有一个 Unit Of Work 在抽象之上有一个抽象( DbContext )当然,这是一种反模式,或者至少是不必要的。

    我有以下问题:

    我有一个通用的 IRepository 像这样:

    public interface IGenericRepository<TEntity> where TEntity : class
    {
        IEnumerable<TEntity> Get(
            Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            string includeProperties = "");
    
        TEntity GetByID(object id);
    
        void Insert(TEntity entity);
    
        void Delete(object id);
    
        void Delete(TEntity entityToDelete);
    
        void Update(TEntity entityToUpdate);
    }
    

    这就是这个接口的实现:

    public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
    {
        internal GymHelperContext context;
        internal DbSet<TEntity> dbSet;
    
        public GenericRepository(GymHelperContext context)
        {
            this.context = context;
            dbSet = context.Set<TEntity>();
        }
    
        public virtual IEnumerable<TEntity> Get(
            Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            string includeProperties = "")
        {
            IQueryable<TEntity> query = dbSet;
    
            if (filter != null)
            {
                query = query.Where(filter);
            }
    
            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }
    
            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            else
            {
                return query.ToList();
            }
        }
    
        public virtual TEntity GetByID(object id)
        {
            return dbSet.Find(id);
        }
    
        public virtual void Insert(TEntity entity)
        {
            dbSet.Add(entity);
        }
    
        public virtual void Delete(object id)
        {
            TEntity entityToDelete = dbSet.Find(id);
            Delete(entityToDelete);
        }
    
        public virtual void Delete(TEntity entityToDelete)
        {
            if (context.Entry(entityToDelete).State == EntityState.Detached)
            {
                dbSet.Attach(entityToDelete);
            }
            dbSet.Remove(entityToDelete);
        }
    
        public virtual void Update(TEntity entityToUpdate)
        {
            dbSet.Attach(entityToUpdate);
            context.Entry(entityToUpdate).State = EntityState.Modified;
        }
    }
    

    我有一个名为Facade的项目,它实例化了一个映射器和一个工作单元,如下所示:

    public class MuscleFacade
        {
            private readonly UnitOfWork _unitOfWork = new UnitOfWork();
            private readonly MuscleMapping _muscleMapping = new MuscleMapping();
    
            public MuscleFacade()
            {
    
            }
    
            public IEnumerable<MuscleViewModel> GetAllMuscles()
            {
                var source = _unitOfWork.MuscleRepository
                    .Get()
                    .ToList();
    
                var result = source.Select(x => _muscleMapping.MuscleToModel(x));
    
                return result;
            }
    
            public GymViewModel GetGymViewModel()
            {
                GymViewModel gymViewModel = new GymViewModel
                {
                    ListOfMuscles = GetAllMuscles().ToList()
                };
    
                return gymViewModel;
            }
    
        }
    

    这个 MuscleFacade 类它是我用autopac在控制器上注入的,我注入一个 IMuscleFacade 在其构造函数中。

    现在的问题是,我的 MuscleTypeViewModel 有一览表 MuscleViewModel 这些模型与它们的域类对应物映射在一起,在这个特定的例子中是 MuscleType 有许多 Muscle (例如:手臂有二头肌、三头肌等),所以我把导航属性放在每个手臂上,就像这样:

    public class MuscleType : IEntity
    {
        public int Id { get; set; }
    
        [StringLength(100)]
        public string MuscleTypeName { get; set; }
    
        public ICollection<Muscle> Muscles { get; set; }
    }
    
    public class Muscle : IEntity
    {
        public int Id { get; set; }
    
        [StringLength(100)]
        public string MuscleName { get; set; }
    
        public int MuscleTypeId { get; set; }
    
        public MuscleType MuscleType { get; set; }
    }
    

    现在让我们看看 GetAllMuscles 立面中的方法:

    public IEnumerable<MuscleViewModel> GetAllMuscles()
    {
        var source = _unitOfWork.MuscleRepository
            .Get()
            .ToList();
    
        var result = source.Select(x => _muscleMapping.MuscleToModel(x));
    
        return result;
    }
    

    如果我想急于加载musclettype,如何更改get()以接收和 Expression 属于 Func 而不是 string ?

    1 回复  |  直到 6 年前
        1
  •  4
  •   grek40    6 年前

    可以定义一个包含include定义的助手类:

    abstract class IncludeDefinition<TEntity>
    {
        public abstract IQueryable<TEntity> Include(IQueryable<TEntity> entities);
    }
    
    class IncludeDefinition<TEntity, TProperty> : IncludeDefinition<TEntity>
    {
        public IncludeDefinition(Expression<Func<TEntity, TProperty>> includeEx)
        {
            _includeEx = includeEx;
        }
    
        private readonly Expression<Func<TEntity, TProperty>> _includeEx;
    
        public override IQueryable<TEntity> Include(IQueryable<TEntity> entities)
        {
            return entities.Include(_includeEx);
        }
    }
    

    然后使用 IncludeDefinition 在你 Get 方法

    public IEnumerable<Muscle> Get(params IncludeDefinition<Muscle>[] includes)
    {
        IQueryable<Muscle> muscles = ...;
        foreach (var item in includes)
        {
            muscles = item.Include(muscles);
        }
        return muscles.ToList();
    }
    

    并调用方法

    _unitOfWork.MuscleRepository
        .Get(new IncludeDefinition<Muscle, MuscleType>(m => m.MuscleType));
    
    // Include as many as you wish
    _unitOfWork.MuscleRepository
        .Get(new IncludeDefinition<Muscle, MuscleType>(m => m.MuscleType),
             new IncludeDefinition<Muscle, SomeOtherRelatedEntity>(m => m.SomeOtherProperty));
    

    编辑 这里有条路要走 “只包括” 而不是写复杂的语法。

    创建新接口 IQueryRepository 这种支持 得到 没有明确的包含和 Include 推导 IGenericRepository 从这个界面:

    public interface IQueryRepository<TEntity>
         where TEntity : class
    {
        IEnumerable<TEntity> Get(
            Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null);
    
        IQueryRepository<TEntity> Include<TProperty>(Expression<Func<TEntity, TProperty>> referenceExpression);
    }
    
    public interface IGenericRepository<TEntity> : IQueryRepository<TEntity>
         where TEntity : class
    {
        IEnumerable<TEntity> Get(
            Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            params IncludeDefinition<TEntity>[] include);
    
        // other methods like GetByID, Add, Update...
    }
    

    更新 GenericRepository 定义-它使用的方法 包括定义 我最初描述的,它返回 GenericQueryRepositoryHelper 什么时候 包括 被称为。

    public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
    {
        internal DbSet<TEntity> dbSet;
    
    
        public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null)
        {
            return Get(filter, orderBy, new IncludeDefinition<TEntity>[0]);
        }
    
        public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, params IncludeDefinition<TEntity>[] includes)
        {
            IQueryable<TEntity> query = dbSet;
    
            foreach (var item in includes)
            {
                query = item.Include(query);
            }
    
            if (filter != null)
            {
                query = query.Where(filter);
            }
    
            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            else
            {
                return query.ToList();
            }
        }
    
        public IQueryRepository<TEntity> Include<TProperty>(Expression<Func<TEntity, TProperty>> referenceExpression)
        {
            return new GenericQueryRepositoryHelper<TEntity>(this, new IncludeDefinition<TEntity, TProperty>(referenceExpression));
        }
    
        // other methods like GetByID, Add, Update...
    }
    

    实施 GenericQueryRepositoryHelper 存储包含内容并在以下情况下应用它们 得到 被称为

    public class GenericQueryRepositoryHelper<TEntity> : IQueryRepository<TEntity>
        where TEntity : class
    {
        private readonly IList<IncludeDefinition<TEntity>> _includeDefinitions;
        private readonly IGenericRepository<TEntity> _repository;
    
        internal GenericQueryRepositoryHelper(IGenericRepository<TEntity> repository, IncludeDefinition<TEntity> includeDefinition)
        {
            _repository = repository;
            _includeDefinitions = new List<IncludeDefinition<TEntity>> { includeDefinition };
        }
    
        public IEnumerable<TEntity> Get(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null)
        {
            return _repository.Get(filter, orderBy, _includeDefinitions.ToArray());
        }
    
        public IQueryRepository<TEntity> Include<TProperty>(Expression<Func<TEntity, TProperty>> referenceExpression)
        {
            _includeDefinitions.Add(new IncludeDefinition<TEntity, TProperty>(referenceExpression));
            return this;
        }
    }
    

    愉快的查询包括:

    var repo = new GenericRepository<Muscle>(...);
    repo.Include(x => x.MuscleType)
        .Include(x => x.MuscleType.Muscles)
        .Get(x => x.MuscleName == "Test", x => x.OrderBy(m => m.MuscleName));