【问题标题】:How do I deal with database generated id values in a unit of work如何在工作单元中处理数据库生成的 id 值
【发布时间】:2023-03-19 22:15:01
【问题描述】:

警告 我使用 SQL Server 2008 R2 作为持久性框架。我没有改变这一点的选择。我正在使用 Micro-ORM 进行持久化。我也没有改变这一点的选择。第三,我没有将表标识列更改为 guid 的选项。它们必须保持为整数。

我要创建的聚合是一个包含一些任务的项目。我想将此保存到两个表中,一个与父项目有关,另一个与任务有关,由父项目 ID 链接。很简单。显然,表结构是一个持久性细节,我希望将其排除在域模型之外。一旦我坚持这一点,我想将项目的 id 发回给用户,以便他们可以导航到新创建的项目。

public class CreateNewProjectRequest
{
    public int InterestingInteger { get; set; }
    public string MoreDataNeededForRequest { get; set; }
}

public CreateProjectApplicationService
{
    private readonly IUnitOfWork uow;

    public CreateProjectApplicationService(IUnitOfWork uow)
    {
        this.uow = uow;
    }

    public int CreateNewProject(CreateNewProjectRequest request)
    {
        var project = ProjectAggregate.CreateFrom(request);
        var projectRepository = new ProjectRepository(uow);
        projectRepository.Add(project);
        projectRepository.Save(project);
        //db transaction commits
        uow.Commit();
    }
}

参考关于这个主题的几个资源(Vaughn Vernon 的 DDD 书和最新的 Wrox DDD 书模式、原则和领域驱动设计的实践),我看到存储库负责聚合根的持久性。存储库接口位于域模型中。

在 Wrox DDD 书中,存在 UnitOfWorkIUnitOfWorkRepository,定义如下:

public interface IUnitOfWork
{
    void RegisterAmended(IAggregateDataModel entity, IUnitOfWorkRepository unitofWorkRepository);
    void RegisterNew(IAggregateDataModel entity, IUnitOfWorkRepository unitofWorkRepository);
    void Commit();
    void Clear();
}

public interface IUnitOfWorkRepository
{
    void PersistCreationOf(IAggregateDataModel entity);
    void PersistUpdateOf(IAggregateDataModel entity);
    void PersistDeleteOf(IAggregateDataModel entity);
}

public class ProjectRepository : IProjectRepository, IUnitOfWorkRepository
{
    //Simplified for example's sake, I didn't implement all of IUnitOfWorkRepository
    private readonly IUnitOfWork uow;

    public ProjectRepository(IUnitOfWork uow)
    {
        this.uow = uow;
    }

    public void Add(Project project)
    {
        unitOfWork.RegisterNew(project, this);
    }

    public void PersistCreationOf(IAggregateDataModel entity)
    {
        //Persist changes via micro ORM -- new id is available
    }
}

提交的实现创建了一个事务并将其持久化。

我遇到的问题是,当调用 Commit() 方法以将事务持久保存到数据存储时,我有一个在该过程中创建的新 ID。我知道CreateProjectApplicationService 可能会涉及多个聚合(在我的情况下它还没有...),因此工作单元实现在这里管理事务,因此数据存储处于一致状态。

我不能简单地从数据库中播种 id。我想使用 scope_identity() 来获取 db 生成的 id,因为它是一个自动增量列。

获取这个新插入的 id 的最简洁方法是什么?或者,这里的工作单元是不是一个不恰当的抽象,应该留给其他用例?

【问题讨论】:

标签: c# sql-server domain-driven-design ddd-repositories


【解决方案1】:

在 DDD 中,工作单元是 业务流程 本身。你所拥有的是一种流行的反模式。无论如何,考虑到您的约束,最简单的做法是使 Id 属性可分配并将其设置在存储库中。

因此,您的项目将在 repository.Add 方法中获取 id。关于添加任务,那应该是不同的操作,您试图在一个操作中做太多事情。基本上,您使用的是“旧”事务脚本 (CRUD) 方法,但使用的是 DDD 术语。

通常,您应该有一个添加项目的操作 -> ProjectCreated[event] -> AddDefaultTasks。

用户界面也应该更多地基于任务,而不是一次做两件不同的事情。

我想说,当 db 负责生成 id 时,你不能真正做正确的 DDD。关键是,DDD 不是用神奇的配方来修补糟糕的代码库,而是自上而下地进行适当的设计。但是你现在负责打补丁,所以你不能真正做 DDD。

【讨论】:

    猜你喜欢
    • 2011-07-06
    • 1970-01-01
    • 2021-03-02
    • 1970-01-01
    • 2011-09-29
    • 1970-01-01
    • 1970-01-01
    • 2018-03-28
    • 1970-01-01
    相关资源
    最近更新 更多