使用Vaughn Vernon在C#(https://github.com/VaughnVernon/IDDD_Samples)中实现域驱动设计示例,有一个标识类型,所有专用于身份的类都是从这个类型构建的:
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; }
}
使用标识的Calender类:
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; }
}
}
上述身份类提供了什么好处,比如使用更简单的类型(如GUID)或字符串作为标识?
答案 0 :(得分:3)
这归结为我猜想的设计偏好。
前段时间我做了或多或少的同样的事情。我有一个Identity<T>
概念,因为密钥类型可能会有所不同。主要是Guid
,但有时为int
或string
。
我最终放弃了这种做法,因为它增加了比价值更多的开销,因为我的存储库总是知道他们正在处理什么类型和密钥,所以没有必要抽象它。
但是,如果您发现自己有一些泛型位,例如,它们会接受存储库并为您进行Get
调用,那么您可能会发现它很有用。例如:
public class IllGetYourEntity
{
public TEntity Get<TEntity>(IRepository<TKey> repository, Identity id)
{
return repository.Get(id);
}
}
但我甚至使用了更细粒度,特定于角色的存储库接口结构。我宁愿拥有这个:
public interface ICanGet<TEntity, TId)
{
TEntity Get(TId id);
}
public interface ICanAdd<TEntity>
{
void Add(TEntity entity);
}
然后可以由另一个存储库接口使用它们:
public interface ICustomerRepository:
ICanGet<Customer, Guid),
ICanAdd<Customer>
{
}
但如果您不需要,那么一个好的实体特定存储库接口将会:
public interface ICustomerRepository
{
Customer Get(Guid id);
void Add(Customer customer);
}
长话短说:它不会给你太多买,除非真正需要,否则我会放弃它。
答案 1 :(得分:2)
一个原因可能是,当您在有界上下文之间传递标识对象时,标识对象本身会携带创建标识(以及实体)时的日期,并且可能还包含有关其源自的上下文的信息。这在第177页的书中有解释。