我很难找到实施业务规则验证的最佳方法,依赖于存储在数据库中的数据。在下面的简化示例中,我想确保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,但我仍然不清楚哪一层应该负责这种验证。
任何帮助都将不胜感激。
答案 0 :(得分:3)
这几乎是我对其进行建模的方式,除了我将CreateUserService
作为域服务(并在单独的应用程序服务中处理工作单元)。使用这种方法,我不会太害怕域服务和规范之间的紧密耦合,因为用户名唯一性似乎是源自实际业务域的业务规则(这里是“用户和身份验证”有界上下文)
如果您仍然害怕CreateUserService
和规范之间的紧密耦合,您确实可以进一步抽象出规范。似乎是合法的,但要记住YAGNI原则。