我正在使用领域驱动设计坚持的原则重写我的ASP.NET MVC应用程序。 我想验证我的用户实体。 到目前为止,我能够验证基本规则(如用户名和密码是一个非空/空白字符串)。 但是有一条规则,我需要确保用户名是唯一的。 不过,我需要访问数据库序要做到这一点,这意味着我将不得不注入我IUserRepository到我的用户实体,像这样。
public class User
{
private readonly IUserRepository _userRepository;
public User(IUserRepository repo)
{
_userRepository = repo;
}
public override void Validate()
{
//Basic validation code
if (string.IsNullOrEmpty(Username))
throw new ValidationException("Username can not be a null or whitespace characters");
if (string.IsNullOrEmpty(Password))
throw new ValidationException("Password can not be a null or whitespace characters");
//Complex validation code
var user = _userRepository.GetUserByUsername(Username);
if (user != null && user.id != id)
throw new ValidationException("Username must be unique")
}
}
然而,这似乎是...好错了。 让我的实体依赖于我的仓库似乎是一个坏主意(纠正我,如果我错了)。 但其在实体验证码是有道理的。 哪里是把复杂的验证码最好的地方?
然而,这似乎是...好错了。 让我的实体依赖于我的仓库似乎是一个坏主意(纠正我,如果我错了)。
在一般情况下,在库的依赖是不是“错误”,它有时是不可避免。 不过,我认为它应该是一个例外,应避免使用尽可能多地。 在你的情况下,你可能会重新考虑有这种依赖性。 如果你想想看,“独特性”不是实体本身的责任,因为实体不知道其他实体。 那么,为什么有实体强制执行这个规则?
但其在实体验证码是有道理的。 哪里是把复杂的验证码最好的地方?
我认为你可能会overgeneralizing“验证”。 我想摆脱“验证”方法,将确保对象不进入“无效”状态摆在首位。 我回答几个月前,类似的问题。
现在回到唯一性规则。 我认为这是在哪里DDD“泄露”了一下,从某种意义上说,此业务规则的执行不能单纯域代码表示的例子之一。 我想接近它是这样的:
// repository
interface Users {
// implementation executes SQL COUNT in case of relation DB
bool IsNameUnique(String name);
// implementation will call IsNameUnique and throw if it fails
void Add(User user);
}
客户端代码会知道添加新用户之前,应该明确检查的独特性,否则会崩溃。 这种组合强制在域代码的业务规则,但它通常是不够的。 作为一个附加的执行层,你可能需要添加UNIQUE约束在数据库或使用显式锁定。
我在这些类型的情况下使用的模式是将这种类型的验证逻辑的应用程序中的服务。 从某种程度上说,这是有道理的,因为User
实体只对自己的合法性,该组用户的不合法性负责。 创建用户可以looklike这种情况的应用服务方法:
public User CreateUser(string userName)
{
if (this.userRepository.Exists(userName))
throw new Exception();
var user = new User(userName);
this.userRepository.Add(user);
return user;
}
应用程序服务是一种抽象无论您是采用DDD或没有的就是有,因此回落到DDD时摩擦提供了一个好去处。
然而,这似乎是...好错
不,这是没有错的。 具有域模型依赖于一个库是完全正常的。 除了你已经抽象是更好的接口后你的资料库。
或者不使用构造函数注入。 通过资源库的验证方法,如果它是唯一一个需要它:
public class User
{
public void Validate(IUserRepository repo)
{
//Basic validation code
if (string.IsNullOrEmpty(Username))
throw new ValidationException("Username can not be a null or whitespace characters");
if (string.IsNullOrEmpty(Password))
throw new ValidationException("Password can not be a null or whitespace characters");
//Complex validation code
var user = repo.GetUserByUsername(Username);
if (user != null && user.id != id)
throw new ValidationException("Username must be unique")
}
}
我同意@oleksii, 使用规范模式是一个更好的办法。 验证在不同的上下文不同的含义,所以这对我来说很有意义分裂这个问题。