创建域对象

问题描述 投票:1回答:1

我正在创建一个以员工和雇主作为域对象的应用程序。他们都有一个User对象的引用,我存储密码和其他帐户相关的东西。

例:

public class Employee
{
    public Guid EmployeeId { get; set; }
    public User User { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public string About { get; set; }
    ...
    //other properties
}

public class Employer
{
    public Guid EmployerId { get; set; }
    public User User { get; set; }
    public string CompanyName { get; set; }
    public string CompanyDescription { get; set; }
    public string FoundedYear { get; set; }
    ...
    //other properties
}

public class User
    public Guid UserId { get; set; }
    public string Email { get; set; }
    public string PasswordHash { get; set; }
    ...
   //other properties
}

我也在使用应用程序服务,其中方法代表单个用例。假设我有RegisterEmpolyee方法,应该将员工保存到数据库,将其角色设置为“Employee”并发送验证邮件。

这是我现在的代码。我正在使用Asp Net.Core.Identity.UserManager来创建用户帐户:

    public async Task<EmployeeDto> RegisterEmployee(RegisterEmployeeDto employee)
    {
        var validateResult = _validatorService.Validate(employee);
        if (!validateResult.IsValid)
            throw new ServerException
                ("RegisterEmployeeDto is not valid", validateResult.GetErrors());

        await _db.BeginTransactionAsync();
        var newUser = new User { UserName = employee.Email, Email = employee.Email };
        var userCreationResult = await _userManager.CreateAsync(newUser, employee.Password);

        if (!userCreationResult.Succeeded)
        {
            var userCreationErrors = userCreationResult.GetIdentityResultErrors();
            throw new ServerException("Error during create User account.", userCreationErrors);
        }

        await _roleService.AddUserToRoleAsync(newUser.Id, ApplicationRoles.Employee);
        var verificationCode = await _userManager.GenerateEmailConfirmationTokenAsync(newUser);
        newUser.VerificationCode = verificationCode;

        await _emailService.SendActivationEmail(newUser.Email, newUser.Id, verificationCode);

        var newEmployee = new Employee(employee.Name, employee.Surname, newUser);

        await _db.Employees.AddAsync(newEmployee);
        await _db.CompleteAsync();

        var employeeDto = _mapper.Map<Employee, EmployeeDto>(newEmployee);

        _db.CommitTransaction();

        return employeeDto;
    }

以下是我的问题:

  1. 根据DDD,这段代码和我的方法是否合适?
  2. 我应该将员工的创建提取到域名服务吗?或者工厂?如果是这样,我应该从那里调用存储库方法? (我的意思是服务当然)
  3. 假设应该将员工的创建提取到域服务。我应该在内部创建用户吗?

像这样:

    public async Task<Employee> CreateEmployee(RegisterEmployeeDto employee)
    {
        var newUser = new User { UserName = employee.Email, Email = employee.Email };
        var userCreationResult = await _userManager.CreateAsync(newUser, employee.Password);

        if (!userCreationResult.Succeeded)
        {
            var userCreationErrors = userCreationResult.GetIdentityResultErrors();
            throw new ServerException("Error during create User account.", userCreationErrors);
        }

        var newEmployee = new Employee(employee.Name, employee.Surname, newUser);
        //Should I call repository here? 
        await _db.Employees.AddAsync(newEmployee);
        await _db.CompleteAsync();

        return newEmployee;
    }

或者可以将User作为参数传递?

  1. 最后一个问题:检查我想要创建的用户是否存在的正确位置在哪里?申请服务是否适合这样做?

提前感谢您的回答。

c# asp.net-core domain-driven-design
1个回答
0
投票

从我看来,UserEmployeeEmployer是聚合根(AR)。

根据DDD,这段代码和我的方法是否合适?

在DDD中,不建议聚合引用除by ID之外的其他聚合。你的EmployeeEmployer AR有这么糟糕的参考,所以不行。相反,EmployeeEmployer应该只包含一个UserId字段。

我应该将员工的创建提取到域名服务吗?或者工厂?如果是这样,我应该从那里调用存储库方法? (我的意思是服务当然)

从我所看到的,你有一个创建多个聚合的复杂过程。在DDD中,您不能在单个事务中以原子方式执行此操作。相反,每个Aggregate都在自己的事务中创建/变异。然而,有一种协调长期过程的战术模式:Saga /流程经理。

您应该定义一个将员工注册为Saga的过程:RegisterEmployee。这个过程应该有这些方法的接口:createstartcontinuecreate方法接收开始处理所需的所有数据。 start方法尝试运行各个步骤(如createEmployee,createUser等);如果start方法再次运行,它应该从停止的地方继续,所以Saga应该记录它的状态。

通过将Aggregates上的命令设置为幂等,可以使架构更好。这样,当Saga重新启动时,它可以再次将所有命令发送给Aggregates;这有效地使Saga非常简单。

假设应该将员工的创建提取到域服务。我应该在内部创建用户吗?

该域名服务实际上是上一步的Saga。但是Saga不应该包含属于Aggregates的逻辑!小心不要使你的领域模型贫血。佐贺应该只包含协调逻辑!

最后一个问题:检查我想要创建的用户是否存在的正确位置在哪里?申请服务是否适合这样做?

什么意味着用户已经存在?已有用户使用该用户名?如果是,那么最简单的解决方案是在username列上有一个唯一索引,如果可能的话。如果不可能(即你启用了分片),那么你可以让另一个Saga检查重复项并向管理员或其他人报告。

© www.soinside.com 2019 - 2024. All rights reserved.