我见过很多关于实现存储库和工作单元的文章。我还看过有关如何添加额外复杂性的文章,因为DbContext已经在使用存储库和工作单元模式。
我将重构一个几乎每个实体都有一个存储库的应用程序,并希望尽可能多地删除复杂性。
任何人都可以解释/提供文章/博客/等链接,解释如何使用DbContext而不是我自己的存储库吗?
答案 0 :(得分:5)
private readonly AppContext context = new AppContext();
放在每个控制器的顶部。您也许可以将两者结合起来,但如果数据层发生变化,您仍然需要修改每个查询类。
我认为这里的主要问题是每个人都在努力实现不同的目标。 Rob的建议方法是为了保持DRY。就个人而言,我抽象数据层的目的是为了能够在以后轻松切换数据访问方法。也许那是因为我过去已经被烧掉了,选择了一些获取数据的方法,从长远来看,这些方法最终无法理解。但我们至少都同意,实现存储库的传统方式是一个坏主意。
事实上,这是一个没有真正答案的问题。在某种程度上,您必须做最适合您和您的应用的事情。我已经解决的方法有点类似于存储库模式,我使用泛型方法而不是泛型类。如下所示:
public class Repository : IRepository
{
protected readonly DbContext context;
public Repository(DbContext context)
{
this.context = context;
}
public IEnumerable<TEntity> GetAll<TEntity>()
{
var dbSet = context.Set<TEntity>;
return dbSet.ToList();
}
...
}
我的实际课程比这复杂得多,但这足以说明要点。首先,注入上下文。这是我强烈不同意Rob的一个领域。也许如果你在你的上下文中快速和松散地玩,你可能不知道“它来自哪里”,但我使用依赖注入容器,它根据我的上下文请求创建一个实例。换句话说,我知道完全它来自哪里。
其次,因为这是一个带有泛型方法的标准旧类,所以我不需要在我的控制器操作中新建它们。我也不必为每个实体定义单独的存储库类。我可以简单地将这一个依赖项注入我的控制器并滚动:
public class FooController : Controller
{
private readonly IRepository repo;
public FooController(IRepository repo)
{
this.repo = repo;
}
...
}
然后,如果我想获取一些Foo
,我就这样做:
repo.GetAll<Foo>();
或者我想要一些Bar
:repo.GetAll<Bar>()
。
然后,您可以通过通用约束开始做有趣的事情。假设我希望能够只提取“已发布”的项目。我需要的只是一个界面:
public interface IPublishable
{
PublishStatus Status { get; }
DateTime? PublishDate { get; }
DateTime? ExpireDate { get; }
}
然后,我只是将我希望成为“可发布”的任何实体实现此接口,或者从实现它的抽象类继承。一旦完成设置,我现在可以在我的存储库中执行以下操作:
public IEnumerable<TEntity> GetAllPublished<TEntity>()
where TEntity : IPublishable
{
var dbSet = context.Set<TEntity>();
return dbSet.Where(m =>
m.Status == PublishStatus.Published &&
m.PublishDate.HasValue && m.PublishDate.Value <= DateTime.Now &&
(!m.ExpireDate.HasValue || m.ExpireDate.Value > DateTime.Now)
).ToList();
}
现在,我在一个存储库中有一个方法可以为实现IPublishable
的任何实体提取已发布的项目。代码重复是最基本的,更重要的是,如果我需要使用不同的ORM甚至是Web API来切换数据访问层,我只需要更改这个存储库类。我的所有其余代码都很愉快,好像什么都没发生一样。