使用DbContext和DbSet代替实现存储库和工作单元 [英] Using DbContext and DbSet instead of implementing repositories and unit of work

查看:213
本文介绍了使用DbContext和DbSet代替实现存储库和工作单元的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经看到很多有关实现存储库和工作单元的文章.我还看过有关如何执行此操作只是增加了额外复杂性的文章,因为DbContext已经在使用存储库和工作单元模式.

I have seen plenty of articles about implementing repositories and a unit of work. I have also seen articles about how doing this is just adding extra complexity, because the DbContext is already using the repository and unit of work pattern.

我将重构一个几乎每个实体都有一个存储库的应用程序,并希望消除尽可能多的复杂性.

I will be refactoring an application that pretty much has a repository for each entity, and would like to remove as much complexity as possible.

谁能解释/提供指向文章/博客/等的链接,这些链接解释了如何使用DbContext而不是我自己的存储库?

Can anyone explain/provide links to articles/blogs/etc that explain how to use the DbContext instead of my own repositories?

推荐答案

罗伯·科纳里(Rob Conery)是个很聪明的人,但是我对此并不同意他的意见.他建议的Command/Query方法只是从操作中删除查询逻辑(这是一些,但不多).仍然没有真正的抽象.并且,基本控制器方法也不是很好.尽管数据访问方法(这里是ORM)仅抽象到代码中的一个位置,以便将来进行一些更轻松的更改,但它并没有抽象出用于该数据层的API,因此几乎变得毫无意义. .它真正为您节省的唯一事情就是必须将private readonly AppContext context = new AppContext();放在每个控制器的顶部.您也许可以将两者结合起来,但是如果您的数据层发生变化,那么您仍在考虑必须修改这些查询类中的每一个.

Rob Conery's a smart guy, but I have to disagree with him on this one. Command/Query method he suggests just removes the query logic from the action (which is something, but not much). There's still no true abstraction. And, the base controller method is not great either. While the method of data access (here, an ORM) is abstracted to just one place in your code, making for somewhat easier changes in the future, it does nothing to abstract the API for working with that data layer, so it almost becomes pointless. The only thing it really saves you from is having to put private readonly AppContext context = new AppContext(); at the top of every controller. You could perhaps combine the two, but then you're still looking at having to modify every one of those query classes if your data layer changes.

我认为这里的主要问题是每个人都在尝试实现不同的目标. Rob的建议方法旨在保持干燥.就我个人而言,我抽象数据层的目标是在以后轻松切换数据访问方法的能力.也许那是因为过去我一直被选择某种获取数据的方法所困扰,而从长远来看,这种方法最终并不能理想地解决问题.但是,我们至少可以同意,实现存储库的 traditional 方法不是一个好主意.

I think the chief problem here is that everyone is trying to achieve something different. Rob's suggested approaches are geared towards staying DRY. Personally, my goal in abstracting the data layer is for the easy ability to switch out data access methods at a later point. Perhaps that's because I've been burned in the past by choose some method of getting at data that ended up not working out ideally in the long run. We can at least both agree, though, the traditional way of implementing repositories is a bad idea.

实际上,这是一个没有真正答案的问题.在某种程度上,您必须要做最适合您和您的应用程序的事情.我确定的方法有点类似于存储库模式,我使用通用方法而不是通用类.类似于以下内容:

In truth, this is a problem with no true answer. To a certain extent you have to just do what works best for you and your application. The method I've settled on is somewhat akin to the repository pattern, I use generic methods instead of a generic class. Something like the following:

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的领域.也许,如果您在上下文中玩得很快而松散,则可能不知道它来自哪里",但是我使用了一个依赖项注入容器,该容器为我的上下文请求创建了一个实例.换句话说,我确切地知道它来自哪里.

My actual class is much more complex than that, but that's enough to illustrate the main points. First, the context is injected. This is one area where I strongly disagree with Rob. Perhaps if you're playing fast and loose with your context you may not know "where it came from", but I use a dependency injection container which creates one instance per request of my context. In other words, I know exactly where it came from.

第二,因为这是一个带有泛型方法的标准旧类,所以我不需要在控制器操作中添加一堆新方法.我也不必为每个实体定义单独的存储库类.我可以简单地将这个依赖项注入控制器并滚动:

Second, because this is a standard old class with generic methods, I don't need to new up a bunch of them in my controller actions. I also don't have to define a separate repository class for each entity. I can simply inject this one dependency into my controller and roll:

public class FooController : Controller
{
    private readonly IRepository repo;

    public FooController(IRepository repo)
    {
        this.repo = repo;
    }

    ...
}

然后,如果我想获取一些Foo,我就这样做:

Then, if I want to fetch some Foos, I just do:

repo.GetAll<Foo>();

或者如果我想要一些Bar:repo.GetAll<Bar>().

Or if I want some Bars: repo.GetAll<Bar>().

然后,您可以通过通用约束开始做一些非常有趣的事情.假设我希望只能提取已发布"的项目.我需要的是一个像这样的界面:

Then, you can start to do really interesting things via generic constraints. Let's say I'd like to be able to pull out only items that are "published". All I need is an interface like:

public interface IPublishable
{
    PublishStatus Status { get; }
    DateTime? PublishDate { get; }
    DateTime? ExpireDate { get; }
}

然后,我只是简单地使想要发布"的任何实体都实现此接口,或者从实现该接口的抽象类继承.设置完成后,我现在可以在存储库中执行以下操作:

Then, I simply make whatever entities I want to be "publishable" implement this interface or inherit from an abstract class that implements it. Once that's all set up, I can now do something like the following in my repository:

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等其他方式切换数据访问层,则只需要更改此存储库类即可.我所有的其余代码都愉快地跳动,好像什么也没发生.

Now, I have one method in one repository that can pull out just the published items for any entity that implements IPublishable. Code duplication is at a bare minimum, and more importantly, if I need to switch out the data access layer with something else like a differ ORM or even a Web API, I just have to change this one repository class. All the rest of my code happily chugs along as if nothing happened.

这篇关于使用DbContext和DbSet代替实现存储库和工作单元的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆