我应该在哪里进行DDD的独特检查?

时间:2009-06-15 20:51:01

标签: c# repository domain-driven-design entity

我正在研究我的第一个DDD项目,我想我了解实体,数据访问对象及其关系的基本角色。我有一个基本的验证实现,它将每个验证规则与它的关联实体一起存储。这适用于仅适用于当前实体的规则,但在需要其他数据时会崩溃。例如,如果我有一个用户名必须唯一的限制,我希望IsValid()调用在存在具有当前名称的现有用户时返回false。

但是,我没有找到任何干净的方法来保持实体本身的验证规则。我想在实体上有一个IsNameUnique函数,但是执行此操作的大多数解决方案都需要我注入用户数据访问对象。这个逻辑应该在外部服务吗?如果是这样,我如何仍然保持与实体本身的逻辑?或者这是应该在用户实体之外的东西吗?

谢谢!

3 个答案:

答案 0 :(得分:3)

我喜欢塞缪尔的回应,但为了简单起见,我建议实施Specification。您创建一个返回布尔值的规范,以查看对象是否满足特定条件。将IUs​​erRepository注入规范,检查用户是否已存在该名称,并返回布尔结果。

public interface ISpecification<T>
{
  bool IsSatisfiedBy(TEntity entity);
}

public class UniqueUsernameSpecification : ISpecification<User>
{
  private readonly IUserRepository _userRepository;

  public UniqueUsernameSpecification(IUserRepository userRepository)
  {
    _userRepository = userRepository;
  }

  public bool IsSatisfiedBy(User user)
  {
    User foundUser = _userRepository.FindUserByUsername(user.Username);
    return foundUser == null;
  }
}

//App code    
User newUser;

// ... registration stuff...

var userRepository = new UserRepository();
var uniqueUserSpec = new UniqueUsernameSpecification(userRepository);
if (uniqueUserSpec.IsSatisfiedBy(newUser))
{
  // proceed
}

答案 1 :(得分:2)

在DDD中,有一个名为aggregate的概念。它基本上负责应用程序内的一致性。

恕我直言,特别是在这种情况下,我猜CustomerRepository会出现类似“Customer aggregate”的内容,而Customer类就是聚合根。

然后,root将负责执行所有这些操作,并且没有其他人可以访问CustomerRepository选项。还有一些可能性:

  • 如果名称不是唯一的(并且客户会捕获并返回错误,或类似的东西),CustomerRepository可能会抛出异常。
  • CustomerRepository可以有一个IsValidUserName(),客户在做其他事情之前会调用它
  • 您可以想到的任何其他选项

答案 2 :(得分:1)

我要说这完全超出了DDD的范围。

DDD所拥有的是一组产生有用模型的事件。但是,这些模型之间的数据关系不一定是可能的。

您使用的是哪种一致性模型?

如果您可以在ACID事务中提交多个事件,则可以确保对一组聚合的更改以原子方式发生。

如果您使用最终一致性模型,则可能无法在以后实际验证这些内容。当你这样做时,你可能需要补偿那些据说发生但不再有效的事情。

必须在上下文中回答唯一性。如果模型很小(数千个),则可以使用聚合表示要使其唯一的值集。假设可以进行组聚合交易。

如果没有,那么,您只需将模型投影到支持唯一性约束的数据库。如果此投影失败,则必须返回到聚合,并以某种方式将其标记为无效。你需要考虑失败。这就是分布式长时间运行的过程,比如saga模式可能很有用,但也需要你考虑其他事情。

总之,如果您不能使用具有强一致性的存储模型,那么一切都变得更加复杂。 lot 。也就是说,在分布式环境中管理故障有很好的,完整的模式,但它可以解决问题,因为现在你需要考虑故障,在整个过程的每一点,这是一个好的,但需要更多的时间投资。