【问题标题】:DDD : Can a repository access another repository?DDD:一个存储库可以访问另一个存储库吗?
【发布时间】:2020-02-23 16:02:24
【问题描述】:

我不熟悉 DDD。 我检查了以下回复:Can a repository access another by DDD? 在询问之前,但找不到任何相关信息。

在我的应用程序中,我有一个包含另一个对象作为属性的对象。 我有一个主要对象的存储库,但是为了检索属性的值,需要访问另一个存储库。

我的问题是:第一个存储库应该访问第二个存储库,还是应用程序调用这两个存储库并将它们合并;

例如:

对于两个类:

public class Foo1
{
    public int Id { get; set; }

    // .... More data

    public Foo2 foo2 { get; set; }
}

public class Foo2
{
    public int Id { get; set; }

    public int Type { get; set; }
}

代码应该是这样的:

public class Foo1Repository
{
    public Foo1 Get() { 
        return new Foo1();
    }
}

public class Foo2Repository
{
    public Foo2 Get(int foo1Id)
    {
        return new Foo2();
    }
}

public class Application
{
    public void main()
    {
        Foo1 foo1 = new Foo1Repository().Get();
        foo1.foo2 = new Foo2Repository().Get(foo1.Id);
    }
}

或更多类似:

public class Foo1Repository
{
    public Foo1 Get() {
        Foo2Repository foo2Repository = new Foo2Repository();
        Foo1 foo1 = new Foo1();
        foo1.foo2 = foo2Repository.Get(foo1.Id);

        return foo1;
    }
}

public class Foo2Repository
{
    public Foo2 Get(int foo1Id)
    {
        return new Foo2();
    }
}

public class Application
{
    public void main()
    {
        Foo1 foo1 = new Foo1Repository().Get();
    }
}

当然,我很想知道是否有更好的架构?

谢谢!

【问题讨论】:

  • 这个问题可能更适合Software Engineering堆栈交换(并得到更好的回应)
  • @AvrahamL 我认为您不需要 Foo2 的特定存储库。在我看来,您可以简单地在 Foo1 的存储库上创建一个方法来检索此类属性,因为它是 Foo1 域的一部分
  • @Padro,感谢您的回复。问题是 Foo2 可以从系统的其他部分单独调用。这意味着它是一个业务部门。此外,这种和平信息存储在另一个提供程序中,如 Foo1。鉴于此,您仍然认为它们属于同一个存储库吗?
  • @AvrahamL 根据您的描述,Foo2 似乎具有聚合根 的特征,因此需要自己的存储库。然而,Foo1 实体不能直接引用Foo2,方法是保存Foo2 类型的字段。而Foo1 必须只为Foo2标识符 保存一个字段。我的回答中的第二种情况进一​​步解释了。

标签: c# .net domain-driven-design


【解决方案1】:

DDD 建议将一个存储库用于检索和存储一个聚合根;聚合根是实体,在域中具有重要作用。 实体的修改必须通过聚合根进行:检索聚合根及其存储库,进行必要的修改,然后将其存储回来。聚合根的组成实体不得单独检索和修改,因此没有它们的存储库。

在您的情况下,根据上下文,Foo1 似乎是聚合根。对于Foo1,只有一个存储库就足够了; Foo2 的存储库是多余的。在检索到Foo1 实例后,您可以而且必须修改Foo1 的属性Foo2Foo1Foo2 不得单独检索和修改,从而无需 Foo2 存储库。

但是,同样取决于上下文,如果您发现 Foo2Foo1 本身是一个聚合根,那么只有它才值得拥有自己的存储库。但是,在这种情况下,Foo1 不得持有对Foo2 的引用(即对另一个聚合根的直接引用,不建议这样做)并在事务中对其进行修改。相反,它必须仅通过其标识符引用Foo2,如下所示:

public class Foo1
{
    public int Id { get; set; }

    // .... More data

    public int foo2Id { get; set; } // Foo2 identfier only, not a Foo2 instance
}

public class Foo2
{
    public int Id { get; set; }

    public int Type { get; set; }
}

如果修改Foo1 需要对Foo2 进行相同的修改,则必须通过Foo1 持有的标识符检索Foo2 来完成,如以下示例所示。请注意,为简单起见,该示例修改了同一事务中的两个聚合根。然而,这种修改通常发生在最终一致的单独事务中。

Foo1 foo1 = foo1Repository.findById(foo1Id);

// modify foo1 state

Foo2 foo2 = foo2Repository.findById(foo1.foo2Id);

// modify foo2 state

// persist changes
foo1Repository.store(foo1);
foo2Repository.store(foo2);

【讨论】:

    【解决方案2】:

    不,不应该。您没有按预期完全实现存储库概念。

    存储库只是一个持久化 DDD 对象的接口。我认为没有通用语言要求,这将需要一个存储库来包含另一个存储库。换句话说,您的主题专家永远不会说“应该将用户保存到数据库内的平面文件中”之类的话;这没有意义。

    您的第一个示例最接近 DDD。但请注意,存储库和工厂之间存在细微差别,严格来说newing up 域对象属于工厂或属于聚合一部分的工厂方法(这通常更适合 UL)。 因为存储库旨在持久化域对象,所以它们往往与 Persistence APIs(如数据库 APIs)进行大量交互。因此,如果您需要一个存储库来聚合两个数据库,例如,您需要与存储库中的两个不同 API 进行交互,而您的使用者应该对此细节一无所知。

    【讨论】:

      猜你喜欢
      • 2011-02-21
      • 2012-03-10
      • 2012-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-15
      • 2010-11-24
      相关资源
      最近更新 更多