持久无知的域层

时间:2011-12-06 09:58:47

标签: c# domain-driven-design

我的编程语言是C#。我在域模型中有一个关于持久性无知的问题。

我们假设我有一个这样的人类:

public class Person
{
    private string email;

    public string Email
    {
        get { return email; }
        set { email = value; }
    }

    public Person(string email)
    {
        this.email = email;
    }
}

现在,在我的域模型中,有一条规则,即不能有两个人拥有相同的电子邮件地址。因此,在实例化新人时,需要验证以及更改电子邮件属性时。所以我想知道如何在持久性无知域层中解决这样的验证。我目前所做的是使用工厂模式进行人员实例化,我在其中注入人员存储库。在那里,我可以搜索具有相同电子邮件地址的其他人。像这样:

public class PersonFactory
{
    private static readonly IPersonRepository personRepository;

    public Person CreateNewPerson(string email)
    {
        Person personWithSameMail = personRepository.GetPersonByEmail(email);

        if (personWithSameMail != null)
            throw new ApplicationException("Email already exists.");

        return new Person(email);
    }

    public PersonFactory(IPersonRepository personRepository)
    {
        this.personRepository = personRepository;
    }
}

但是使用此解决方案时,更改人员电子邮件地址(可能是有效的商业案例)时的检查仍未涵盖。此外,Person类仍然公开了一个公共构造函数,并且绕过工厂,仍然可以使用具有重复电子邮件地址的人。

对此有任何解决方案吗?

P.S。以数据为中心的所有人:不,我不想在数据访问层验证欺骗性电子邮件;)

更新:

无论如何,整个问题可能已经过时了。根据域模型上下文检查重复的电子邮件总是需要知道所有人的“某事” - 根。 “某事”可以是地址簿,也可以是包含所有具有电子邮件地址的人的整个世界。所以也许我正在混淆程序员需要技术上优雅的问题解决方案,这只是因为缺乏一个完整且经过深思熟虑的领域模型。这可以是这种情况吗?不仅仅有一个人在太空中漂浮着一个电子邮件地址(嘿,空间将是我在这里的聚合根;))只是为了存在的乐趣?但是,如果这是一个真实的商业案例,如地址簿应用程序,地址簿将是人的集合根,因此可以检查其内部集合中的所有人,以确保没有重复的电子邮件地址。

1 个答案:

答案 0 :(得分:2)

我不是DDD专家,但我对它的看法是这样的。

首先,对我而言,您设计中最大的缺陷是允许实体上的设置者。这意味着您可以改变您的实体的状态,而无需聚合根知道它。我会重构它删除setter并让它在创建对象时通过构造函数设置它。

另一点。人员实体不应该对电子邮件进行验证(以检查电子邮件是否已被使用的形式),因为如果她是聚合的根,它只能知道它自己的状态和相关的子实体。那么你应该从实体中引用存储库,这对我来说是糟糕的设计。这就是为什么你使用了我认为的工厂。

我认为首先应该在UI中进行验证,以便尽快失败。但这还不够。在保持域名状态时,您应该强制执行该人员拥有唯一电子邮件的规则。我认为验证应该在域服务中进行,例如名为 PersonRegistrationService ,它将引用 IPersonRepository 并在添加人员实体之前为了保持其收集,它将首先检查这些人的电子邮件是否是唯一的。如果不是,我会通知用户错误而不添加实体。

您怎么看?