在实现DDD一书中,提到了创建TenantId
值对象。这对我来说很有意义,因为GUID
可能是空的而不是有效的TenantId
,所以通过创建TenantId
值对象我可以防止这种情况(我还有其他值) Name
,PhoneNumber
,EmailAddress
等对象:
public class TenantId
{
public TenantId(Guid id)
{
this.SetId(id);
}
public Guid Id { get; private set; }
private void SetId(Guid id)
{
if (id == Guid.Empty)
{
throw new InvalidOperationException("Id must not be an empty GUID.");
}
this.Id = id;
}
}
我感兴趣的是,我应该或不应该在服务方法上使用TenantId
,例如:
TenantId tenantId = new TenantId(model.TenantId); // model.TenantId being a GUID.
this.tenantService.GetTenant(tenantId);
或者我应该在服务方法参数中使用更原始的表单:
this.tenantService.GetTenant(model.TenantId); // again model.TenantId is a GUID.
这本书似乎有时会以某种方式,有时却是另一种方式。人们对这些方法的利弊有何看法?
答案 0 :(得分:3)
如果服务不需要对实体的限制访问,请传递值对象,因为它是shared identifier,但我会将其编码为:
public class TenantId : IEquatable<TentantId>
{
public TenantId(Guid id)
{
if (id == Guid.Empty)
{
throw new InvalidOperationException("TenantId must not be an empty GUID.");
}
_id = id;
}
private readonly Guid _id;
public Equals(TentantId other)
{
if (null == other) return false;
return _id.Equals(other._id);
}
public GetHashcode()
{
return _id.GetHashcode();
}
public override Equals(object other)
{
return Equals(other as TenantId);
}
public ToString()
{
return _id.ToString();
}
}
但是在某些情况下,应该仅使用用户可以在存储库中访问的实体来调用域服务:在这些情况下,域服务的公共接口需要实体(即使实现只使用标识符)
答案 1 :(得分:1)
我更喜欢使用自定义值对象作为聚合的标识。我认为当其他开发人员想要调用api时,它会提供更多线索。考虑一下:
Tenant findBy(String identity); //others may pass an String instance but not id and the compliler can't check it out for you
您无法在下面添加以下方法:
Tenant findBy(String name);//assuming name unique but it failed for compiling
如果您已经拥有特定类型,为什么要使用原始类型?
修改强>
我通常使用自定义类型存储库和应用程序服务,对于域服务,请参阅@Giacomo Tesio的答案。我认为“直接使用实体”更有意义。