我有一个帐户对象,可以像这样创建一个用户;
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);
}
}
在我的服务层创建新用户时,我调用此方法。但是,有一个规则,用户的电子邮件必须是该帐户的唯一,所以这是什么?对我来说,它应该在CreateUser方法中使用额外的行来检查该电子邮件是否对该帐户是唯一的。
但是,如果要这样做,那么该帐户的所有用户都需要加载,这对我来说似乎有些开销。查询数据库中的用户电子邮件会更好 - 但是在方法中执行此操作会要求帐户对象中的存储库不是吗?也许答案就是从存储库加载帐户而不是执行;
var accountRepository.Get(12);
//instead do
var accountRepository.GetWithUserLoadedOnEmail(12, "someone@example.com");
然后,帐户对象仍然可以检查用户集合中的电子邮件,如果找到它,它将被急切地加载。
这有用吗?你会做什么?
我正在使用NHibernate作为ORM。
答案 0 :(得分:1)
如果您已正确指定users表上的约束,则add应抛出异常,告知您已存在重复值。您可以在CreateUser方法中捕获该异常并返回null或一些重复的用户状态代码,或者让它流出并稍后捕获它。
你不想测试它是否存在于你的代码中然后添加,因为在测试和添加之间有一点点可能会有人出现并添加相同的电子邮件会导致异常无论如何抛出......
public User CreateUser(string email)
{
try
{
User user = new User(email);
user.Account = this;
user.Insert();
catch (SqlException e)
{
// It would be best to check for the exception code from your db...
return null;
}
}
答案 1 :(得分:1)
首先,我认为您不应该使用异常来处理“正常”的业务逻辑,例如检查重复的电子邮件地址。这是一个很好的文档反模式,最好避免使用。保持对数据库的约束并处理任何重复的异常,因为它们是无法避免的,但请尝试通过检查将它们保持在最低限度。我不建议锁定桌子。
其次,您已将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;
}
}
这允许您稍微分离责任并使用域服务来协调事物。希望有所帮助!
答案 2 :(得分:0)
鉴于“用户电子邮件必须对帐户唯一的规则”,那么最重要的是在数据库架构中指定电子邮件是唯一的,这样如果电子邮件重复,数据库INSERT将失败
您可能无法阻止两个用户几乎同时添加相同的电子邮件,因此接下来就是代码应该(优雅地)处理INSERT失败原因。
完成上述操作后,在执行插入操作之前查看电子邮件是否唯一是可选的。