存储库模式与工作单元或 ActiveRecord 的对齐程度如何

发布于 2024-08-07 16:37:17 字数 1190 浏览 6 评论 0原文

尽管我没有进行全面的 DDD,但我发现存储库模式很有吸引力,并且我确实尝试沿着聚合根边界对存储库进行分段。我在实体框架之上实现存储库,这里的 ObjectContext 允许工作单元样式,因为它跟踪实体的更改,并在调用 SaveChanges 时生成适当的 SQL。

关于何时调用 SaveChanges,我正在我的存储库中使用两种不同的方法 - 区别似乎在于我是采用工作单元还是活动记录语义。如果我定义一个存储库接口,如下所示:

public interface IRepository<T>
{
    T Get(int id);
    IList<T> GetAll();
    IQueryable<T> Query();
    void Delete(T entity);
    void Add(T entity);
    IUnitOfWork GetUnitOfWork();
}

并将 IUnitOfWork 定义为

public interface IUnitOfWork
{
    void SaveChanges();
}

然后在 Add(T 实体) 实现中,我似乎有两个选择:

    public void Add(Document entity)
    {
        DB.AddToDocumentSet(entity);
        GetUnitOfWork().SaveChanges();  //delegates to the ObjectContext's SaveChanges
    }

    public void Add(Document entity)
    {
        DB.AddToDocumentSet(entity);
    }

在前一种情况下,存储库的 Add 方法在每个操作上发送 SQL。在后一种情况下,调用代码负责从存储库获取工作单元,并在认为合适时调用 SaveChanges。这允许工作单元跨越不同的存储库(我确保每个存储库在其构建中获得相同的工作单元)。

我的直觉是第二种方法更灵活。采用工作单元模式还意味着对实体的更新要好一些,因为调用代码只需更新存储库返回的实体的属性,然后调用 UnitOfWork.SaveChanges。

使用存储库模式时,一种方法通常比另一种方法更受青睐吗?

Although I'm not doing full blown DDD, I find the repository pattern appealing and I do try to segment the repositories along aggregate-root boundaries. I'm implementing repositories on top of the Entity Framework, and here the ObjectContext allows for a unit-of-work style as it tracks changes to the entities and will generate the appropriate SQL when SaveChanges is called.

I'm struggling with two different approaches within my repositories around when to call SaveChanges -- and the difference seems to be whether I'm adopting unit-of-work or active record semantics. If I define a repository interface to look like this:

public interface IRepository<T>
{
    T Get(int id);
    IList<T> GetAll();
    IQueryable<T> Query();
    void Delete(T entity);
    void Add(T entity);
    IUnitOfWork GetUnitOfWork();
}

and IUnitOfWork to be

public interface IUnitOfWork
{
    void SaveChanges();
}

Then in the Add(T entity) implementation, I seem to have two choices:

    public void Add(Document entity)
    {
        DB.AddToDocumentSet(entity);
        GetUnitOfWork().SaveChanges();  //delegates to the ObjectContext's SaveChanges
    }

or

    public void Add(Document entity)
    {
        DB.AddToDocumentSet(entity);
    }

In the former case, the repository's Add method is sending the SQL on each operation. In the latter case, the calling code is responsible for obtaining the unit of work from the repository and calling SaveChanges when it deems appropriate. This allows the unit of work to span different repositories (I'm ensuring that each repository gets the same unit of work in its construction).

My gut feel is that the second approach is more flexible. Adopting the unit of work pattern also means that updates to entities are a bit nicer in that calling code simply updates properties on entities returned by the repositories and then calls UnitOfWork.SaveChanges.

When using the repository pattern, is one approach generally favored over the other?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

百合的盛世恋 2024-08-14 16:37:17

这取决于您没有说明的故障模式要求。这主要是如何处理工作单元期间发生的故障的问题。尽管还可能存在其他更复杂的变体,但您基本上有两种选择:

  1. 保存工作单元期间发生的所有更改,直至失败。
  2. 回滚工作单元期间由于故障而发生的所有更改。

第一个 Add 方法更适合场景 1,第二个 Add 方法更适合场景 2。

场景 1 可能需要智能应用程序代码以允许用户在故障点恢复。场景 2 在应用程序端更容易实现,但如果用户在 9 步流程中执行 8 步而失败,则可能会让用户感到沮丧。

It depends on your failure mode requirements, which you haven't stated. This is primarily an issue of how to handle failures that occur during your unit of work. You have basically two choices, although there are other more complex variants possible:

  1. Save all changes that occurred during the unit of work up until the failure.
  2. Rollback all changes that occurred during the unit of work due to the failure.

Your first Add method is more appropriate for scenario 1 and your second Add method is more appropriate for scenario 2.

Scenario 1 likely requires smart application code to allow the user to resume at the point of failure. Scenario 2 is easier to implement on the application side, but may frustrate the user if they were, for instance, 8 steps into a 9 step process when it failed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文