DDD - 实体的仓库依赖验证

4

我在尝试找出最佳实现业务规则验证的方法,这些规则取决于存储在数据库中的数据。在下面简化的示例中,我希望确保Username属性是唯一的。

public class User() {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public string GenerateRandomPassword() {

    }
}

public interface IUserRepository : IRepository<User>
{
    bool UsernameTaken(string username);
}

public interface IUnitOfWork : IDisposable
{
    void Commit();
    IUserRepository Users { get; }
}

我已经阅读了很多关于实现此目标的不同方法的内容,包括将仓库注入实体(并防止其处于无效状态)、创建扩展方法等。
然而,我认为这些都不是最好的方法。
因此,我决定使用应用程序服务来协调实体验证,使用规范进行验证。
public class CreateUserService : ICreateUserService
{
    private readonly IUnitOfWork _uow;

    public CreateUserService(IUnitOfWork uow)
    {
        _uow = uow;
    }

    public User Create(User user)
    {
        var usernameAvailableSpecification = new UsernameAvailableSpecification(_uow.Users);

        if (!usernameAvailableSpecification.IsSatisfiedBy(user))
        {
            throw new ValidationException("Username already taken");
        }

        user.GenerateRandomPassword();

        _uow.Users.Store(user);
        _uow.Commit();

        return user;
    }
}

起初,这似乎是个不错的选择。但由于服务与规范实现的耦合度很高,并且必须手动处理规范的依赖关系,因此它很难进行单元测试。我考虑将规范抽象化,但我不确定是否正确。
也有可能是我开始做错了,因为实际上我正在学习DDD,并且还没有清楚地了解哪一层应该负责这种验证。
任何帮助都将不胜感激。
1个回答

3
这几乎是我的建模方式,除了我会将CreateUserService作为域服务(并在单独的应用服务中处理工作单元)。采用这种方法,我不会太担心域服务和规范之间的紧密耦合,因为用户名的唯一性似乎是源自实际业务领域(这里是“用户和认证”有界上下文)的业务规则。
如果您仍然担心CreateUserService和规范之间的紧密耦合,您确实可以进一步抽象规范。这似乎是合理的,但请记住YAGNI原则。

谢谢您的回答。我已经尝试了您建议的方法,并且取得了成功。同时,我接受它作为答案。再次感谢。 - otaviosoares

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接