Создание доменных объектов - PullRequest
       14

Создание доменных объектов

0 голосов
/ 11 сентября 2018

Я создаю приложение с работником и работодателем в качестве объекта домена.У них обоих есть ссылка на объект 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, который должен сохранять сотрудника в базе данных, установить для него роль «Сотрудник» и отправить подтверждение по электронной почте.

Это мой код прямо сейчас.Я использую AspNet.Core.Idenity.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 Ответ

0 голосов
/ 11 сентября 2018

Из того, что я вижу, User, Employee и Employer - Совокупные корни (AR).

В порядке ли этот код и мой подход согласно DDD?

В DDD не рекомендуется, чтобы агрегат имел ссылки на другие агрегаты, отличные от , по идентификатору .Ваши Employee и Employer AR имеют такую ​​ плохую ссылку, так что это не нормально.Вместо этого Employee и Employer должны содержать только поле UserId.

Должен ли я извлечь создание сотрудника в службу домена?Или может быть заводской?И если так, я должен вызвать метод хранилища оттуда?(Я имею в виду услугу, конечно)

Из того, что я вижу, у вас сложный процесс создания нескольких агрегатов.В DDD вы не можете сделать это атомарно, внутри одной транзакции.Вместо этого каждый Агрегат создается / мутирует в своей собственной транзакции.Однако существует тактическая схема координации длительного процесса: Saga / Process manager.

Вы должны определить процесс регистрации сотрудника в качестве Saga: RegisterEmployee.Этот процесс должен иметь интерфейс с этими методами: create, start, continue.Метод create получает все данные, необходимые для запуска процесса.Метод start пытается выполнить отдельные шаги (например, createEmployee, createUser и т. Д.);если метод start будет запущен снова, он должен продолжить с того места, где остановился, поэтому Сага должна записать свой статус.

Архитектуру можно улучшить, сделав команду для Агрегатов как идемпотентную.Таким образом, когда Сага перезапускается, она может снова отправить все команды Агрегатам;это фактически делает Saga очень простым.

Допустим, следует извлечь создание сотрудника из службы домена.Должен ли я создать пользователя внутри себя тогда?

Эта доменная служба фактически является сагой из предыдущего шага.Однако Сага не должна содержать логику, которая принадлежит Агрегатам!Будьте осторожны, чтобы не сделать вашу модель домена анемичной.Сага должна содержать только координирующую логику!

И последний вопрос: где находится правильное место для проверки, существует ли пользователь, которого я хочу создать, или нет?Является ли служба приложений подходящим местом для этого?

Что означает, что пользователь уже существует?Уже есть пользователь с таким именем?Если да, то самое простое решение - по возможности иметь уникальный индекс в столбце username.Если это невозможно (т. Е. У вас включен шардинг), у вас может быть другая Saga, которая проверяет дубликаты и сообщает администратору или что-то в этом роде.

...