开发者

The cleaner approach to write code which parses DTO's

In the current project we have decided to use dto's to transfer data between the server and the client.

Dto's are flat, flattering is not the issue, it can be done without much troubles. But dto unflattering may become much difficult to implement, because user may delete, create and update some parts of the flattened entity graph.

So this is example code for one of the web service methods:

    [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;
        }
    } 

As you can see there are a lot of stuff mixed here: context creation data selection calling to data updater sending id of newly created dto's back to the client

Things starts to be getting worth when you see how EmployeeBackgroundUpdater is implemented:

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.Passpo开发者_如何学编程rt = 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;
    }
}

The code is same in structure, the only difference is the types of Entity sets and Entity types. And this is scary, because I will have to rewrite same code in a bunch of different places along the projects if we will choose to update validation logic or something similar.

Thank you for reading to this point. And there is a set of questions from me:

1) How to parse flat dto's, which can have child objects, to the valid entity graph?

2) Should dto (or presentation model maybe) contain hierarchy of objects?

3) How to get rid of the repeating code?


For parsing entities to DTOs and vice-versa you can check AutoMapper. DTO can be hierarchy of objects(it doesn't have to be flatten). I'm afraid that you will never avoid some repeating code because each entity type is somehow special and you have to deal with it manually - that is the complexity included in using DTOs.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜