gpt4 book ai didi

c# - IRepository 和工作单元与预加载

转载 作者:行者123 更新时间:2023-11-30 15:15:14 26 4
gpt4 key购买 nike

我知道有一个 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);
}

这是这个接口(interface)的实现:

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 的项目,它实例化了一个 Mapper 和一个 UnitOfWork,如下所示:

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 类是我使用 Autofac 在我的 Controller 上注入(inject)的类,我在其构造函数中注入(inject)了一个 IMuscleFacade

现在的问题是,我的 MuscleTypeViewModel 有一个 MuscleViewModel 列表,这些模型映射到它们的领域类对应物,在这个特殊情况下是一个 MuscleType 有许多 Muscle(例如:Arm 有二头肌、三头肌等)所以我在每个肌肉上放置了导航属性,如下所示:

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

现在让我们再看看 Facade 中的 GetAllMuscles 方法:

public IEnumerable<MuscleViewModel> GetAllMuscles()
{
var source = _unitOfWork.MuscleRepository
.Get()
.ToList();

var result = source.Select(x => _muscleMapping.MuscleToModel(x));

return result;
}

如果我想要 Eager-Load MuscleType,我该如何更改 Get() 以便接收 FuncExpression 而不是 string ?

最佳答案

您可以定义一个包含您的包含定义的辅助类:

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支持 Get没有显式包含和 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定义 - 它使用 IncludeDefinition 的方法我最初描述的,它返回一个 GenericQueryRepositoryHelper什么时候Include被称为。

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存储包含并在 Get 时应用它们被称为

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

关于c# - IRepository 和工作单元与预加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52930931/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com