Architecture 实体标识-使用类作为标识而不是简单类型

Architecture 实体标识-使用类作为标识而不是简单类型,architecture,domain-driven-design,software-design,Architecture,Domain Driven Design,Software Design,Vaughn Vernon在C#()中实现了域驱动设计示例,其中有一种标识类型,所有专用于标识的类都是从该类型构建的: public class CalendarId : Identity { public CalendarId() { } public CalendarId(string id) : base(id) { } } 身份类别: public abstract class Identity : IEquatable<Iden

Vaughn Vernon在C#()中实现了域驱动设计示例,其中有一种标识类型,所有专用于标识的类都是从该类型构建的:

public class CalendarId : Identity
{
    public CalendarId() { }

    public CalendarId(string id)
        : base(id)
    {
    }
}
身份类别:

public abstract class Identity : IEquatable<Identity>, IIdentity
{
    public Identity()
    {
        this.Id = Guid.NewGuid().ToString();
    }

    public Identity(string id)
    {
        this.Id = id;
    }

    // currently for Entity Framework, set must be protected, not private.
    // will be fixed in EF 6.
    public string Id { get; protected set; }

    public bool Equals(Identity id)
    {
        if (object.ReferenceEquals(this, id)) return true;
        if (object.ReferenceEquals(null, id)) return false;
        return this.Id.Equals(id.Id);
    }

    public override bool Equals(object anotherObject)
    {
        return Equals(anotherObject as Identity);
    }

    public override int GetHashCode()
    {
        return (this.GetType().GetHashCode() * 907) + this.Id.GetHashCode();
    }

    public override string ToString()
    {
        return this.GetType().Name + " [Id=" + Id + "]";
    }
}
public interface IIdentity
{
    string Id { get; }
}
日历类使用的标识如下:

public class Calendar
{
    public Calendar(Tenant tenant, CalendarId calendarId, string name, string description, Owner owner, IEnumerable<CalendarSharer> sharedWith = null)
    {
         // ... store passed parameters, including identity
         this.id = id;
    }

    CalendarId calendarId;

    public CalendarId CalendarId
    {
        get { return this.calendarId; }
    }
}
公共类日历
{
公共日历(租户租户、日历ID日历ID、字符串名称、字符串描述、所有者、IEnumerable sharedWith=null)
{
//…存储传递的参数,包括标识
this.id=id;
}
CalendarId CalendarId;
公共日历ID日历ID
{
获取{返回this.calendarId;}
}
}

与使用更简单的类型(例如GUID或标识字符串)相比,上面的标识类提供了什么好处?

我想这取决于设计偏好

不久前,我做了差不多相同的事情。我有一个
Identity
概念,因为密钥类型可能会有所不同。主要是
Guid
,但有时是
int
string

我最终放弃了这种做法,因为它增加了比价值更多的开销,而且我的存储库总是知道它们处理的是什么类型和键,因此没有必要对其进行抽象

但是,如果您发现自己拥有一些通用位,例如,接受存储库并为您调用
Get
,那么您可能会发现它很有用。例如:

public class IllGetYourEntity
{
    public TEntity Get<TEntity>(IRepository<TKey> repository, Identity id)
    {
        return repository.Get(id);
    }
}

长话短说:它不会给你买太多东西,除非有真正的需要,否则我会放弃它。

我想这可以归结为设计偏好

不久前,我做了差不多相同的事情。我有一个
Identity
概念,因为密钥类型可能会有所不同。主要是
Guid
,但有时是
int
string

我最终放弃了这种做法,因为它增加了比价值更多的开销,而且我的存储库总是知道它们处理的是什么类型和键,因此没有必要对其进行抽象

但是,如果您发现自己拥有一些通用位,例如,接受存储库并为您调用
Get
,那么您可能会发现它很有用。例如:

public class IllGetYourEntity
{
    public TEntity Get<TEntity>(IRepository<TKey> repository, Identity id)
    {
        return repository.Get(id);
    }
}

长话短说:它不会给你带来太多的好处,除非有真正的需要,否则我会放弃它。

一个原因可能是,当你在有界上下文之间传递标识对象时,标识对象本身带有标识(以及实体)创建的日期,并且可能还包含有关它起源的上下文的信息。这在第177页的书中有解释。

一个原因可能是,当您在有界上下文之间传递标识对象时,标识对象本身携带标识(以及实体)创建的日期,并且还可能包含有关其起源上下文的信息。这在第177页的书中有解释。

如果您有一个方法签名,它将多个
Guid
s作为参数,例如
somethod(Guid tenantId,Guid customerId)
,它可以帮助防止将它们混合在一起,从而具有更具体的类型
somethod(tenantId tenantId,customerId,customerId)
CustomerId
也比
Guid
更符合普遍使用的语言。如果您有一个方法签名,将多个
Guid
s作为参数,例如
someMethod(Guid tenantId,Guid CustomerId)
,它可以帮助防止将它们混合在一起,从而具有更具体的类型
someMethod>(TenantId、TenantId、CustomerId、CustomerId)
CustomerId
也比
Guid
更符合无处不在的语言。
public interface ICustomerRepository: 
    ICanGet<Customer, Guid), 
    ICanAdd<Customer> 
{
}
public interface ICustomerRepository
{
    Customer Get(Guid id);
    void Add(Customer customer);
}