C# 哪个类应该负责为实体创建ID?

C# 哪个类应该负责为实体创建ID?,c#,domain-driven-design,C#,Domain Driven Design,我正在为下面的问题挣扎。假设我想管理项目中的依赖项,这样我的域就不会依赖于任何外部内容——在这个存储库问题上。在本例中,假设我的域位于project.domain中 为此,我在project.Domain中为我的存储库声明了接口,我在project.Infrastructure中实现了该接口。阅读Vernon的DDD红皮书时,我注意到,他建议将为聚合创建新ID的方法放在存储库中,如下所示: public class EntityRepository { public EntityId N

我正在为下面的问题挣扎。假设我想管理项目中的依赖项,这样我的域就不会依赖于任何外部内容——在这个存储库问题上。在本例中,假设我的域位于
project.domain

为此,我在
project.Domain
中为我的存储库声明了接口,我在
project.Infrastructure
中实现了该接口。阅读Vernon的DDD红皮书时,我注意到,他建议将为聚合创建新ID的方法放在存储库中,如下所示:

public class EntityRepository
{
    public EntityId NextIdentity()
    {
        // create new instance of EntityId
    }
 }
在这个
EntityId
对象中应该是GUID,但我想显式地为我的ID建模,所以我不使用普通GUID。我也知道我可以完全跳过这个问题,在数据库端生成GUID,但是为了这个参数,让我们假设我真的想在我的应用程序中生成它

现在我只是在想——有没有什么具体的原因让这个方法像Vernon建议的那样放在存储库中,或者我可以在实体内部实现身份创建,比如像

public class Entity
{
    public static EntityId NextIdentity()
    {
        // create new instance of EntityId
    }
 }

是的,您可以绕过对存储库的调用,只在实体上生成标识。然而,问题是您打破了存储库背后的核心思想:将与实体存储相关的所有内容与实体本身隔离

我想说的是,在respository中保留NextIdentity方法,并且仍然使用它,即使您只生成GUID的客户端。这样做的好处是,在将来需要更改标识的种子方式时,可以通过存储库提供支持。然而,如果您直接在实体上使用这种方法,那么您将不得不在以后重构以支持这种更改

也可以考虑在这样的情况下使用不同的存储库的场景,比如测试。例如,您可能希望生成具有相同ID的两个标识,并执行冲突测试或“此操作是否正确失败”。有一个存储库来处理生成过程,可以让您有机会以这种方式进行创新,而不必制作完全独特的测试用例,这些测试用例不会模拟实际的生产调用


TLDR;将其保存在存储库中,即使您的标识符可以由客户端生成。

您可以将其放置在存储库中,正如Vernon所说,但另一个想法是在创建标识符的基本实体的构造函数中放置工厂。这样,您甚至在与存储库交互之前就拥有了标识符,并且可以根据您的ID生成策略定义实现。存储库可以包括到某些东西的连接,例如web服务或数据库,这些东西可能代价高昂且不可用

有一些好的策略()可以很好地处理标识符。这也使您的应用程序完全独立于外部世界

这还允许您在需要时在整个应用程序中使用不同的标识符类型

例如

public abstract class Entity<TKey>
{
    public TKey Id { get; }

    protected Entity() { }

    protected Entity(IIdentityFactory<TKey> identityFactory)
    {
        if (identityFactory == null)
            throw new ArgumentNullException(nameof(identityFactory));

        Id = identityFactory.CreateIdentity();
    }
}
公共抽象类实体
{
公钥Id{get;}
受保护实体(){}
受保护实体(IIdentialFactory identityFactory)
{
if(identityFactory==null)
抛出新ArgumentNullException(nameof(identityFactory));
Id=identityFactory.CreateIdentity();
}
}

不遵循您试图解决的问题。GUID在统计上是唯一的。GUID实际上与此问题没有直接关系。我只是把我的技术类型隐藏在抽象后面,所以现在我可以使用guid,但稍后我可以通过非常复杂的算法生成id。在这种方法中,当我想更改另一种类型的GUID时,我的所有代码都会编译,测试都会通过,因为我只更改了一些技术细节(在本例中,我在DB中使用哪种类型来区分实体)。不理解当GUID可用时为什么需要复杂的算法。在这种情况下,没有理由使用GUID以外的其他内容。然而,我的问题并不是一个具体的案例。当您使用GUID时,可能会出现一些情况,但随后切换到其他ID—例如,当您希望ID携带的信息多于ID值本身时。这可能是以特定格式生成的数字,例如,有一些控制数字以确保其正确性。然而,在这种情况下,这并不重要:-)帮不了你。嵌入信息是唯一的ID通常不是一个好的计划。