Более чистый подход к написанию кода, который анализирует DTO - PullRequest
2 голосов
/ 02 июня 2011

В текущем проекте мы решили использовать dto для передачи данных между сервером и клиентом.

Dto плоские, лестно не проблема, это можно сделать без особых хлопот.Но реализовать нелестное представление может быть очень сложно, потому что пользователь может удалять, создавать и обновлять некоторые части сплющенного графа сущностей.

Итак, это пример кода для одного из методов веб-службы:

    [Update, EmpresaHasPermissions("PERMIT_INS_Employee")]
    public void UpdateBackground(EmployeeBackgroundDTO dto)
    {
        using (var context = GetObjectContext())
        {
            var user = EmpresaAuthentication.Current.User;

            Employee employee = context.Employees
                .Include(it => it.Nationality)
                .Include(it => it.EthnicOrigin)
                .Include(it => it.MaritalStatus)
                .Include(it => it.Religion)
                .Include(it => it.CRB)
                .Include(it => it.Passport)
                .Single(it => it.OwnerOrganizationId == user.OrganizationId &&
                              !it.Deleted && it.Id == dto.Id);

            var updater = new EmployeeBackgroundUpdater(context);

            updater.UpdateEntity(employee, dto);

            context.SaveChanges();

            dto.MaritalStatusId = employee.MaritalStatusId;
            dto.EthnicOriginId = employee.EthnicOriginId;
            dto.ReligionId = employee.ReligionId;
        }
    } 

Как вы можете видеть, здесь смешано много вещей: выбор данных для создания контекста, вызывающий средство обновления данных, отправляющее идентификатор вновь созданного dto обратно клиенту

Когда вы видите, дела начинают приносить пользукак реализован EmployeeBackgroundUpdater:

public override void UpdateEntity(Employee employee, EmployeeBackgroundDTO dto)
{
    employee.InjectFrom(dto);

    if (!IsPassportNull(dto))
    {
        if (employee.Passport == null)
        {
            employee.Passport = new Passport();
        }

        employee.Passport.IssueDate = dto.PassportIssueDate.Value;
        employee.Passport.ExpiryDate = dto.PassportExpiryDate.Value;
        employee.Passport.PassportNo = dto.PassportPassportNo;
        employee.Passport.IssuingCountryId = dto.PassportIssuingCountryId.Value;
        employee.Passport.OwnerUserId = UserId;
    }
    else
    {
        if (employee.Passport != null)
        {
            DeleteObject(employee.Passport);
            employee.Passport = null;
        }
    }

    if (!IsCRBNull(dto))
    {
        if (employee.CRB == null)
        {
            employee.CRB = new CRB();
        }

        employee.CRB.IssueDate = dto.CRBIssueDate.Value;
        employee.CRB.ExpiryDate = dto.CRBExpiryDate.Value;
        employee.CRB.Registration = dto.CRBRegistration;
        employee.CRB.Notes = dto.CRBNotes;
    }
    else
    {
        if (employee.CRB != null)
        {
            DeleteObject(employee.CRB);
            employee.CRB = null;
        }
    }

    var epmpresaContext = (EmpresaEntities)ObjectContext;

    AddMaritalStatus(employee, dto, epmpresaContext);

    AddReligion(employee, dto, epmpresaContext);

    AddEthnicOrigin(employee, dto, epmpresaContext);

    employee.NationalityId = dto.NationalityId;
}

private void AddMaritalStatus(Employee employee, EmployeeBackgroundDTO dto, EmpresaEntities epmpresaContext)
{
    if (!dto.MaritalStatusId.HasValue && !String.IsNullOrWhiteSpace(dto.MaritalStatusDescription))
    {
        var item = epmpresaContext.MaritalStatuses.FirstOrDefault(
            it => it.Description.ToUpper() == dto.MaritalStatusDescription.ToUpper());

        if (item == null)
        {
            employee.MaritalStatus = new MaritalStatus
            {
                Description = dto.MaritalStatusDescription
            };
        }
        else
        {
            employee.MaritalStatus = item;
        }
    }
    else
    {
        employee.MaritalStatusId = dto.MaritalStatusId;
    }
}

Код имеет одинаковую структуру, единственное отличие состоит в типах наборов сущностей и типах сущностей.И это страшно, потому что мне придется переписывать один и тот же код в разных местах проектов, если мы решим обновить логику валидации или что-то подобное.

Спасибо, что дочитали до этого момента.И у меня есть ряд вопросов:

1) Как разобрать плоские dto, которые могут иметь дочерние объекты, в действительный граф сущностей?

2) Должен dto (или модель представления)возможно) содержать иерархию объектов?

3) Как избавиться от повторяющегося кода?

1 Ответ

4 голосов
/ 02 июня 2011

Для анализа сущностей в DTO и наоборот вы можете установить AutoMapper .DTO может быть иерархией объектов (это не обязательно должно быть сведено).Я боюсь, что вы никогда не будете избегать повторяющегося кода, потому что каждый тип сущности является чем-то особенным, и вам приходится иметь дело с ним вручную - это сложность, связанная с использованием DTO.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...