DDD中对象验证和持久性验证之间的区别?

时间:2012-01-10 13:56:47

标签: validation domain-driven-design

现在,我有一个名为StyleBundle的域名实体。这个StyleBundle有一个样式列表:

public class StyleBundle
{
    public StyleBundle(List<Style> styles)
    {
        this.Styles = styles;
    }

    public IEnumerable<Style> Styles { get; private set;}
}

因此,在我的原始设计中,永远不应该使用空样式列表创建StyleBundle。领域专家基本上认为这是一条很好的规则。

我在构造函数中使用了一个guard子句写了这个:

if (styles.Count() == 0)
   throw new Exception("You must have at least one Style in a StyleBundle.");

确保我无法在无效状态下创建StyleBundle。我认为异常是有道理的b / c在没有至少一个Style的情况下创建的StyleBundle在系统中是特殊的。

当然,在项目的其余部分进行了改变,现在应该可以让用户创建一个没有样式的StyleBundle,但不应该允许他们在没有样式的情况下PURIST一个StyleBundle。

所以现在我正在查看我的guard子句,并意识到我不能再从构造函数中抛出异常了。

继续前进,我有一个服务/应用程序层,我的代码隐藏在他们使用StyleBundles时与之交互。在我的服务层中,我有一个StyleBundleService类,该类向UI公开基本功能......其中包括“CreateStyleBundle”。

似乎我必须检查我的服务层以查看StyleBundle在持久存储到数据库之前是否有任何样式,但是关于这个决定的事情对我来说感觉“错误”。

任何人遇到类似的事情?基本上,当“new'ed up”时对象的状态与同一对象在持久性方面的状态之间的差异是什么?

谢谢! 麦克

4 个答案:

答案 0 :(得分:6)

我会向您的实体添加IsValid方法。这将检查实体当前是否处于有效状态(在您的情况下,检查是否存在样式)。

可以从Repository调用此方法,以检查实体是否可以保留。您可以为特定实体的IsValid方法添加更多规则,并且您可以实现诸如验证错误集合之类的内容,您希望抛出有意义的异常。

答案 1 :(得分:1)

扩展Wouter所说的内容,以及方便的BeforeSaving和BeforeDeleting方法:

public interface IDomainObject<T>
{
    bool IsValid();
}

public interface IEntity<T> : IDomainObject<T>
{

}

public interface IAggregateRoot<T> : IEntity<T>
{
    void BeforeSaving();
    void BeforeDeleting();
}


public interface IAggregateRoot { //or simply IEntity depending on the model
   bool IsValid();
}

public class StyleBundle : IAggregateRoot<T> {
   return styles.Count() > 0
}

public class StyleBundleRepository : Repository<StyleBundle> {
}

public abstract class Repository<T> : IRepository<T> where T : class, IAggregateRoot<T> {

   public T Save(T t)
   {
      t.BeforeSaving(); //for all AggregateRoots, maybe logging what the aggregate was like before the changes

      if(!t.IsValid())
         throw Exeception("Entity invalid");

      EntityStore.Current.SaveChanges();         

      // "AfterSaving" here, i.e.: log how the entity looks after the update

   }
}

编辑:我不亲自使用IsValid的想法,我使用完整的EntityValidationErrors类,我可以在尝试保存之前向客户端报告错误,不应该为空的东西,不应该是空的(如你的样式)等)

答案 2 :(得分:1)

有多种策略:

一些开发人员更喜欢在实体本身中创建2个方法,一个名为IsValid(),它根据业务规则(一般验证)验证实体,另一个名为IsValidForPersistence(),用于验证实体的持久性

关于IsValid()我宁愿不通过验证所有输入来首先允许无效状态,并且支持不变量我使用工厂或构建器。

您可以查看链接http://www.codethinked.com/thoughts-on-domain-validation-part-1 一些想法。

答案 3 :(得分:0)

我知道,这个问题已经有三年了,但看到目前的答案是我想回答的问题。我们正在讨论域数据。因此,不能有一个有0个对象的有效StyleBundle。我想,你有一个前端编辑器,如果你创建一个“新”StyleBundle并且必须添加至少一个样式,然后点击“保存”按钮。

在前端的这一点上,你将没有域对象。您可能有一个数据传输对象,将使用“CreateNewStyleBundle”命令发送。

在我看来,域对象必须与持久性无关,并且应始终处于有效状态。如果你必须调用“IsValid”方法,那么你首先要避免使用域对象。

这只是我的拙见。