简体   繁体   中英

Should one perform a calculation in a DTO model or in the destination entity model?

I'm currently creating various entities in ASP.NET Core 2.2 with accompanying DTOs for a Web API. The client application would submit a DTO object to the relevant controller action. There using the AutoMapper, this would be mapped from the DTO object to an entity object. The resulting entity object would be saved to an entity framework repository which at this moment would be a Microsoft SQL database. For brevity let's assume that the time zones would be irrelevant in this case.

I was just wondering which approach would be more appropriate or to even have not have the calculation in either the DTO or Entity but perhaps within the Controller action.

Note: The actual code is more complicated and involves various calculations for various properties, I have simply chosen a simple case to illustrate my question.

Approach #1

// Entity
public class EventTimes
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    public decimal TotalHours => (decimal)(End - Start).TotalHours;
}

// DTO
public class EventTimesDto
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
}

Approach #2

// Entity
public class EventTimes
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    public decimal TotalHours { get; set; }
}

// DTO
public class EventTimesDto
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }
    public decimal TotalHours => (decimal)(End - Start).TotalHours;
}

It depends on the actual context. Is the EventTimes an entity or is it rather part of your domain model?

Either way I would not put it in the dto as this is really just for transferring data, so it should not contain any logic (besides maybe validation).

Since the responsibility for this calculation is neither part of the dto, nor the entity model's, you could put the heavy calculation in an EventTimesCalculator something like this:

public class EventTimesCalculator
{
    public decimal CalculateTotalHours(EventTimes eventTimes)
    {
        return (decimal)(eventTimes.End - eventTimes.Start).TotalHours;
    }
}

If the EventTimes is part of your business layer / domain model, a more appropriate way would be to have a GetTotalHours() method inside of the model, instead of a property. Of course you would need to map it to the persistence model, if you want to save that information. Then again, since this information can be calculated, you don't need to persist it at all, mainly because the logic might change (example: exclude breaks, interruptions or such).

My advice is to stop thinking in terms of database entities (which I assume you meant above).

At the end, it's rather a detail where you put the calculation logic, more importantly is to have a straight forward design. Is the application monolithic put that logic in your layer that contains the business logic. Is it a distributed architecture, handle the calculation for the model in the service responsible for Eventing. Is it just a small API, keep it simple, put it where you or your team would expect it the most.

Iam using second approach because entity can contain raw which can be modified by application flow.

Common pattern Data transfer object (DTO) is exactly what you want for transport data between application layers which can transform data into desired output. Dto can't contain business logic but also can "prepare", "reduce" data which destination need.

For example:
If presentation layer need totalHours Iam doing this in model instead of entity. Doing this in entity it would lead for endless modifications.

Another example can be user's full name Firstname , Lastname , AcademicDegree .

Entity can hold all of them but

  • one presentation need [academic degree] [firstname] [lastname] and
  • second need data in different format such as [lastname] [firstname] [academic degree].


It is good keep property that make desired format in specific DTO instead of entity IMHO.

I in ASP.NET Core do this in onion architecture and view models and from my experience is easy to manage, change, prepare data for front-end or layers instead of change something in core.

If someone disagrees with me please let comment I like learn something new.

Hope it helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM