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
и спецификацию, вы действительно можете дополнительно абстрагировать спецификацию. Кажется законным, но помни принцип ЯГНИ.