代码之家  ›  专栏  ›  技术社区  ›  Gareth

在哪里检查用户电子邮件还不存在?

  •  3
  • Gareth  · 技术社区  · 17 年前

    我有一个账户对象可以创建这样的用户;

    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方法中加一行,检查电子邮件对帐户是否唯一。

    但是,如果要这样做,那么该帐户的所有用户都需要加载,这对我来说有点开销。为用户的电子邮件查询数据库会更好,但是在方法中这样做需要在account对象中有一个存储库,不是吗?也许答案是当从存储库加载帐户时,而不是这样做;

    var accountRepository.Get(12);
    //instead do
    var accountRepository.GetWithUserLoadedOnEmail(12, "someone@example.com");
    

    然后,account对象仍然可以检查用户集合中的电子邮件,如果找到它,它将被急切地载入。

    这行吗?你会怎么做?

    我用NHibernate作为ORM。

    3 回复  |  直到 8 年前
        1
  •  1
  •   Stefan Moser    17 年前

    首先,我认为您不应该使用异常来处理“正常”的业务逻辑,比如检查重复的电子邮件地址。这是一个很好的文档反模式,最好避免。保留对数据库的约束,并处理任何重复的异常,因为它们无法避免,但请通过检查将其保持在最小值。我不建议锁桌子。

    第二,你已经把ddd标签放在这个问题上了,所以我会用ddd的方式回答它。在我看来,你需要一个域名服务或工厂。一旦您在域服务或工厂中移动了此代码,就可以向其中注入一个用户存储库,并对其进行调用,以查看是否已经存在具有该电子邮件地址的用户。

    像这样:

    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
  •  1
  •   ConsultUtah    17 年前

    如果已经在用户表上正确地指定了约束,则添加操作将引发一个异常,告诉您已经有一个重复的值。您可以在CreateUser方法中捕获该异常并返回空值或某些重复的用户状态代码,或者让它流出并稍后捕获。

    您不想测试代码中是否存在它,然后再添加,因为在测试和添加之间有一点可能性,有人会过来添加同一封电子邮件,因为无论如何都会引发异常…

    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;
        }
    }
    
        3
  •  0
  •   ChrisW    17 年前

    考虑到“用户电子邮件对帐户必须是唯一的规则”,那么最重要的是在数据库模式中指定电子邮件是唯一的,这样,如果电子邮件重复,数据库插入将失败。

    您可能无法阻止两个用户几乎同时添加同一封电子邮件,因此接下来的事情是,代码应该(优雅地)处理由上述原因导致的插入失败。

    在实现了上述功能之后,在插入之前查看电子邮件是否是唯一的,这只是可选的。