DDD - проверки, зависящие от хранилища объекта

Я с трудом пытаюсь найти лучший способ реализовать проверку бизнес-правил, которые зависят от данных, хранящихся в базе данных. В приведенном ниже упрощенном примере я хочу убедиться, что атрибут 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 ответ

Решение

Это почти как я бы смоделировал это, за исключением того, что я бы сделал CreateUserService доменная служба (и обрабатывать единицу работы в отдельной службе приложений). При таком подходе я не стал бы слишком бояться тесной связи между службой домена и спецификацией, поскольку уникальность имени пользователя, по-видимому, является бизнес-правилом, которое происходит в реальном бизнес-домене (здесь, в ограниченном контексте "Пользователь и аутентификация"),

Если вы все еще боитесь сильной связи между CreateUserService и спецификацию, вы действительно можете дополнительно абстрагировать спецификацию. Кажется законным, но помни принцип ЯГНИ.

Другие вопросы по тегам