Gar*_*eth 5 domain-driven-design
我有一个创建对象的帐户对象,就像这样;
public class Account
{
public ICollection<User> Users { get; set; }
public User CreateUser(string email)
{
User user = new User(email);
user.Account = this;
Users.Add(user);
}
}
Run Code Online (Sandbox Code Playgroud)
在我的服务层中,创建新用户时,我调用此方法。但是,有一个规则,即用户电子邮件对于该帐户必须是唯一的,那么该去哪里呢?对我来说,它应该放在CreateUser方法中,并带有额外的一行,该行仅检查电子邮件对于帐户而言是唯一的。
但是,如果要这样做,则将需要加载该帐户的所有用户,这对我来说似乎有些负担。最好在数据库中查询用户的电子邮件-但在该方法中这样做将需要在account对象中存储一个库,不是吗?答案可能就是从存储库加载帐户而不是这样做。
var accountRepository.Get(12);
//instead do
var accountRepository.GetWithUserLoadedOnEmail(12, "someone@example.com");
Run Code Online (Sandbox Code Playgroud)
然后,该帐户对象仍可以检查Users集合中的电子邮件,并且如果找到该电子邮件对象,则将它急切地装入其中。
这样行吗?你会怎么做?
我正在使用NHibernate作为ORM。
首先,我认为您不应该使用异常来处理“正常”业务逻辑,例如检查重复的电子邮件地址。这是一个有据可查的反模式,最好避免。保持对数据库的约束并处理任何重复的异常,因为它们无法避免,但尝试通过检查将它们保持在最低限度。我不建议锁定桌子。
其次,你在这个问题上贴上了DDD标签,所以我就用DDD的方式来回答。在我看来,您需要域服务或工厂。一旦您将此代码移动到域服务或工厂中,您就可以将 UserRepository 注入其中并调用它以查看是否已存在具有该电子邮件地址的用户。
像这样的东西:
public class CreateUserService
{
private readonly IUserRepository userRepository;
public CreateUserService(IUserRepository userRepository)
{
this.userRepository = userRepository;
}
public bool CreateUser(Account account, string emailAddress)
{
// Check if there is already a user with this email address
User userWithSameEmailAddress = userRepository.GetUserByEmailAddress(emailAddress);
if (userWithSameEmailAddress != null)
{
return false;
}
// Create the new user, depending on you aggregates this could be a factory method on Account
User newUser = new User(emailAddress);
account.AddUser(newUser);
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
这允许您稍微分离职责并使用域服务来协调事物。希望有帮助!