我在我的 ASP.NET MVC 程序中使用了类似的方法,到目前为止它运行良好。
我的IUnitOfWork
界面如下所示:
public interface IUnitOfWork
{
IRepository<TEntity> GetRepositoryFor<TEntity>() where TEntity : class;
void SaveChanges();
}
相关的IRepository
界面如下所示:
public interface IRepository<TEntity> : IQueryable<TEntity> where TEntity : class
{
TEntity Find(params object[] keyValues);
void Insert(TEntity entity);
void Update(TEntity entity);
void Delete(TEntity entity);
}
然后像这样将它传递给我的服务:
public abstract class BaseService
{
public BaseService(IUnitOfWork unitOfWork)
{
// etc...
}
}
您是对的,这使得服务可以轻松地解析其存储库,而无需将它们单独传递给构造函数,这在您可能在单个服务中使用多个存储库(例如采购订单和产品)的情况下很有用。
使用这种与 ORM 无关的接口的一个好处是,它意味着您可以轻松地切换 ORM。老实说,我从实体框架更改为另一个 ORM 的机会很小,但事实是,如果需要,我可以。作为奖励,我的服务更容易测试,而且我还发现这使我的服务类更干净,因为它现在完全不知道正在使用的 ORM,并且完全针对上面的两个接口工作。
关于关于通用存储库接口的评论,我的建议是务实,做最适合您和您的应用程序的事情。在 Stackoverflow 上有很多关于这个主题的问题,他们的答案各不相同,关于哪种是最好的方法(EG 暴露IQueryable
vs IEnumerable
,通用 vs 非通用)。
我玩弄没有通用存储库,因为您可能已经注意到我的IRepository
界面看起来像IDbSet
;我采用这种方法的原因是它允许我的实现处理您使用DbContext
EG执行的所有 Entity Framework 实体状态管理内容
public void Delete(TEntity entity)
{
if (Context.Entry(entity).State == EntityState.Detached)
{
EntitySet.Attach(entity);
}
EntitySet.Remove(entity);
}
If I used IDbSet
I would need to perform this in my service layer, which would then require a dependency on DbContext
which seemed a much more leaky abstraction than my generic repository.