【问题标题】:DDD persisting aggregate on 2 different databasesDDD 在 2 个不同的数据库上持久聚合
【发布时间】:2015-12-02 13:32:00
【问题描述】:

我有一个通用IRepository<T>,它在Infrastructure.NHibernate 下实现,使用Simple Injector 将实现注入接口。 IRepository<T> 存在于我的 Domain 中,以便域对象可以使用注入的存储库。

我有一个User``AggregateRoot,其中包含有关应用程序数据库中用户的一些详细信息,IdFirstnameLastname。我知道不关心持久性,但是在这个阶段我们正在讨论这些对象是如何持久化的。

在我的Web.UI(ASP.Net MVC 5) 中,我有一个可以更新用户详细信息的屏幕,FirstnameLastnameEmailAddress。 ID 已存储但无法更新。

当我更新User 详细信息时,我使用IRepository<User> 更新FirstnameLastname

问题:我也需要在我们的OpenLdap 服务器中更新FirstnameLastnameEmailAddress

我有一个Infrastructure.Ldap 项目,所有 Ldap 实现等都在其中。 (存储库、服务、实体、助手、转换器)。

更新 LDap 服务器的最佳方法是什么?

我是否在Domain 中创建另一个ISomeRepository 接口,Infrastructure.Ldap 实现?这意味着我需要向User 添加其他属性,并且只需覆盖 ORM 映射以忽略其他属性。然后我使用IRepositoryISomeRepository 来更新两个数据库中的用户。

或者

Web.UI 已经是一个基础架构问题,所以我只是引用了Infrastructure.Ldap 项目并直接与 ldap 存储库对话,它将使用 LDapUser 对象。这将让我单独更新 Ldap 上的用户。

我很困惑,业务规则是我们需要更新用户详细信息。我假设从 DDD 的角度来看,所有需要更新的细节都需要存在于域中。如何将这个User 保存在 2 个不同的数据存储中?

我的上述选项之一是否有效并通过了良好的实践,或者可能有不同的解决方案?业务需要有 2 个不同的数据存储,因此我需要完成这项工作。

IdFirstnameLastname - 存储在应用程序数据库中以防 Ldap 出现故障,稍后将用于审计目的。

IdFirstnameLastnameEmailAddress - 这存储在用户管理的OpenLdap 服务器部分。

请有人指出我正确的方向。由于对需要在何处进行持久性的限制,很难从 DDD 的角度严格考虑这种情况。如果这一切都在应用程序数据库上,那就很容易了。

【问题讨论】:

  • 如果两种存储机制中的一种没有在单个 ACID 事务中更新,这有关系吗?您能否更新数据库,然后引发最终将更新 LDAP 的事件,反之亦然?
  • 两者需要同时更新,先是Application DB,然后是Ldap。 Ldap 上的用户可以存在于多个应用服务器上。因此,如果他们注销并登录到不同的服务器,则需要了解这些详细信息,因为登录时我们会在身份验证后检查用户详细信息并使用 Ldap 中的内容更新应用程序数据库
  • 如果您的存储库抽象是可组合的,您可以使用Composite 模式来调用 SQL 存储库实现以及 LDAP 存储库实现。然后在SimpleInjector 中,您应该将IRepository<User> 注册为SqlUserRepositoryLdapUserRepository 的组合
  • 我正在使用 fluentnhibernate 和 postgresql,我的 lap 是一个自定义服务实现,它也使用存储库。你介意用一个例子发布一个答案吗?我的存储库被抽象为基础架构。
  • @ArkadiuszK - 我做了一些研究,看起来像是一个可行的解决方案。如果您可以发布带有详细信息的答案,我可以为您接受。我的想法是编写IRepository 的2 个实现,然后将simplinjector 告诉RegisterCollection,我认为这将一个接一个地调用两个存储库。

标签: design-patterns architecture fluent-nhibernate domain-driven-design onion-architecture


【解决方案1】:

您可以在您的存储库中使用Composite 设计模式:

public IRepository<T>
{
    void Save(T entity);
}

public class CompositeRepository<T> : IRepository<T>
{
    private readonly IEnumerable<IRepository<T>> repositories;

    public CompositeRepository(IEnumerable<IRepository<T>> repositories)
    {
        if(repositories == null)
        {
            throw new ArgumentNullException("repositories");
        }
        this.repository = repositories;
    }

    public void Save(T entity)
    {
        foreach(var repository in repositories)
        {
            repository.Save(entity);
        }
    }
}

假设存在SqlUserRepositoryLdapUserRepository 并且都实现了IRepository&lt;User&gt;。然后就可以使用容器注册CompositeUserRepository了:

container.RegisterCollection<IRepository<User>>(new[] { typeof(SqlUserRepository), 
                                                         typeof(LdapUserRepository) });
container.Register<IRepository<User>, CompositeRepository<User>>();

感谢您的服务进一步使用IRepository&lt;User&gt;,并且当您将持久化User 添加到LDAP 时,它们不必更改。我们还通过这种方式解决了这个问题,取得了很好的副作用 - Single Responsibility 存储库上下文中的原则。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-07
    • 2018-08-12
    • 2014-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-20
    • 1970-01-01
    相关资源
    最近更新 更多