Home > Software engineering >  Which layer is the correct place to convert Model to Dto?
Which layer is the correct place to convert Model to Dto?

Time:08-09

I have seen few articles however I need some suggestions/improvements if any, based on my current architecture.

I have created a Repository layer with a Generic Repository pattern, underneath it would be called DynamoDB.

The DynamoDB deals with the Model names and structures that are as good as table names and structures.

My Service Layer references the Contract(domain) layer for Dtos and the repository layer for calling the repo methods.

However the repository layer does not reference the Contract layer, it is required only if I need the mapping from Dtos to model (entity).

Considering the current design, for me the correct place to do mapping of model to dtos is the Service Layer, however, I'm confused about the correct place to do it, as my peers asked me to make a decoupled architecture and they were aligned to do it in the repository layer so that if the repository layer changes it should not affect your other layers.

My question is, whether my architecture is correct, and secondly where the Dto conversion should happen?? Repository layer or Service layer.

enter image description here

My repository layer:

public interface IDbContext<T> where T : class
{
        Task CreateBatchWriteAsync(IEnumerable<T> entities, DynamoDBOperationConfig dynamoDBOperationConfig = null);
        
         Task<List<T>> GetAllItemsAsync(DynamoDBOperationConfig dynamoDBOperationConfig = null);
}
    
public class DbContext<T> : IDbContext<T> where T : class
{
    private readonly Amazon.DynamoDBv2.DataModel.IDynamoDBContext context;
               
    public DbContext(IDynamoDBFactory dynamoDBFactory)
    {
        //
    }     
        
    public async Task CreateBatchWriteAsync(IEnumerable<T> entities, DynamoDBOperationConfig dynamoDBOperationConfig = null)
    {
        // connect to dynamodb
    }
        
    public async Task<List<T>> GetAllItemsAsync(DynamoDBOperationConfig dynamoDBOperationConfig = null)
    {
        // connect to dynamodb
    }
}

public interface IStoreRepository: IDbContext<Store>
{
}
    
public class StoreRepository : IStoreRepository
{
    private readonly IDbContext<Store> _dbContext;

    public TransitSessionRepository(IDbContext<Store> dbContext)
    {
        _dbContext = dbContext;
    }

    public async Task CreateBatchWriteAsync(IEnumerable<Store> entities, DynamoDBOperationConfig dynamoDBOperationConfig = null)
    {
        await _dbContext.CreateBatchWriteAsync(entities,dynamoDBOperationConfig);
    }

    public Task<List<Store>> GetAllItemsAsync(DynamoDBOperationConfig dynamoDBOperationConfig = null)
    {
        await _dbContext.GetAllItemsAsync();
    }
}

Here is my Model in Respository Layer

[DynamoDBTable("Store")]
    public class Store
    {
        [DynamoDBProperty("Code")]
        public string Code { get; set; }

        [DynamoDBProperty("Details")]
        public TransitDetails Details { get; set; }
    }


    public class Details
    {
        [DynamoDBProperty("ClientName")]
        public string ClientName { get; set; }

        [DynamoDBProperty("RequestedBy")]
        public string RequestedBy { get; set; }

        [DynamoDBProperty("CreateDate")]
        public string CreateDate { get; set; }
    }

CodePudding user response:

Please remember that this is an individual assumption for each project.

The IMO service layer will be the best way to do this in your architecture. To make your code cleaner, you can create extension methods like ToEntityModel and ToDTOModel, so you can hide object creation.

The repository layer is the worst place to do this because of the single responsibility principle - the repository should support communication with the database - not parse one model to another.

CodePudding user response:

There is not one agreed way to do this. Individual (per person, per organisatin) styles matter here a lot.

Here are two things to think about:

  1. The smaller the objects a method exposes and accepts the easier it is to refactor. In other words, if you don't expose field X you don't need to worry how it's used.
  2. If the repository returns the full db model the contract changes when the db model changes. If you expose a tailored dto then you have to change the dto if you want to expose more/less information. The 1st requires less work but gives less control and you may end up exposing more than you want.

CodePudding user response:

Repository layer should only return exact data not the DTO.

Main reasons to use repository pattern is to abstracting communication with the database. If you return DTO from repository layer you will violate single responsibility of repository pattern and usage of DTO

Common approach to DTO conversion is "Convert it when you need it" so in your case the best layer to make conversion would be service layer since. Service layer is where your business needs resides

  • Related