如何将Db类映射到通用存储库中的Entity类?

huangapple go评论70阅读模式
英文:

How to map Db class to Entity class in generic repository?

问题

I created a generic repository class where I implement an interface. I follow clean architecture and located UserDbTbl, BaseRepository, and MappingProfile classes in the Infrastructure project, rest of the classes in Domain and Application projects. What's important here is that I use a db-first approach and it can't be changed.

I retrieved UserDbTbl from the database and want to map it to the entity User in BaseRepository. It wouldn't be a problem if I mapped it in a non-generic, dedicated repository (let's say UserRepository). Then I could easily map fields from UserDbTbl to User. The issue is that I want to make the mapping in the generic repository BaseRepository, which implements general methods applicable to various entities (User, Product, and any others).

I don't know how to map it properly in different BaseRepository methods using AutoMapper. As shown in the example below - let's say that, using the ListAllAsync() method, I would like to extract data from some table using _dbContext.Set<T>().ToListAsync() and then try to map it to the generic entity type <T> - in my code I just map it to IReadOnlyList<T>. Not sure if this is okay at all. I have even more problems with other methods, e.g., DeleteAsync. And the final issue - how to create a mapping profile (class MappingProfile)? I have no idea how I could map it generically. The more that the User class has a navigation property to the Address class.

英文:

I created a generic repository class where I implement an interface. I follow clean architecture and located UserDbTbl, BaseRepository and MappingProfile classes in Infrastructure project, rest of the classes in Domain and Application projects. What's important here is that I use db-first approach and it can't be changed.

I retrieved UserDbTbl from db and want to map it to entity User in BaseRepository. It wouldn't be a problem if I mapped it in non-generic, dedicated repository (let's say UserRepository). Then I could easily map fields from UserDbTbl to Users. The issue is that I want to make mapping in generic repository BaseRepository which implements general methods applicable to various entities (Users, Products and any others).

I don't know how to map it properly in different BaseRepository methods using AutoMapper. As shown in the example below - let's say that, using ListAllAsync() method, I would like to extract data from some table using _dbContext.Set&lt;T&gt;().ToListAsync() and then try to map it to generic entity type &lt;T&gt; - in my code I just map it to IReadOnlyList&lt;T&gt;. Not sure if this is ok at all. I have even more problems with other methods e.g. DeleteAsync. And the final issue - how to create mapping profile (class MappingProfile)? I have no idea how could I map it generically. The more that User class have navigation property to Address class.

    // Db Class
    public partial class UserDbTbl
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        public string Division { get; set; }
        public string CreatedBy { get; set; }
        public virtual Address Address { get; set; }
    }

    // Entity class
    public class User
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        public Address Address { get; set; }
    }

    // Generic interface
    public interface IAsyncRepository&lt;T&gt; where T : class
    {
        Task&lt;T&gt; GetByIdAsync(int id);
        Task&lt;IReadOnlyList&lt;T&gt;&gt; ListAllAsync();
        Task&lt;T&gt; AddAsync(T entity);
        Task UpdateAsync(T entity);
        Task DeleteAsync(T entity);
    }

    // Interface implementation
    public class BaseRepository&lt;T&gt; : IAsyncRepository&lt;T&gt; where T : class
    {
        protected readonly RegionManagementDbContext _dbContext;
        private readonly IMapper _mapper;

        public BaseRepository(RegionManagementDbContext dbContext, IMapper mapper)
        {
            _dbContext = dbContext;
            _mapper = mapper;
        }

        public async Task&lt;IReadOnlyList&lt;T&gt;&gt; ListAllAsync()
        {
            var dbDataList = await _dbContext.Set&lt;T&gt;().ToListAsync();
            var domainMap = _mapper.Map&lt;IReadOnlyList&lt;T&gt;&gt;(dbDataList);

            return domainMap;
        }

        public async Task&lt;T&gt; AddAsync(T entity)
        {
            var dbDataAdd = await _dbContext.Set&lt;T&gt;().AddAsync(entity);
            var domainMap = _mapper.Map&lt;T&gt;(dbDataAdd);

            return domainMap;
        }

        public virtual async Task&lt;T&gt; GetByIdAsync(int id)
        {
            var dbDataGetId = await _dbContext.Set&lt;T&gt;().FindAsync(id);
            var domainMap = _mapper.Map&lt;T&gt;(dbDataGetId);

            return domainMap;
        }

        public async Task DeleteAsync(T entity)
        {
            var dbDataDelete = _dbContext.Set&lt;T&gt;().Remove(entity);
            await _mapper.Map&lt;T&gt;(dbDataDelete);
        }

        public async Task UpdateAsync(T entity)
        {
            var dbDataUpdate = _dbContext.Set&lt;T&gt;().Update(entity);
            await _mapper.Map&lt;T&gt;(dbDataUpdate);
        }
    }

    // add mapping profile
    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            CreateMap&lt;typeof(IAsyncRepository&lt;&gt;), typeof(BaseRepository&lt;&gt;)&gt;();
        }
    }

答案1

得分: 1

以下是要翻译的代码部分:

public class BaseRepository<TDbEntity, TDomainEntity>
    where TDbEntity : class
    where TDomainEntity : class
{

    public virtual async Task<TDomainEntity> GetByIdAsync(int id)
    {
        var dbDataGetId = await _dbContext.Set<TDbEntity>().FindAsync(id);
        var domainMap = _mapper.Map<TDomainEntity>(dbDataGetId);

        return domainMap;
    }
}

在映射配置中为每一对实体,如 UserDbTblUser,有这样的部分。

英文:

It might work with having two generic entities for your generic repository, the DB entity and the domain entity.

Something like this:

public class BaseRepository&lt;TDbEntity, TDomainEntity&gt;
    where TDbEntity : class
    where TDomainEntity : class
{

    public virtual async Task&lt;TDomainEntity&gt; GetByIdAsync(int id)
    {
        var dbDataGetId = await _dbContext.Set&lt;TDbEntity&gt;().FindAsync(id);
        var domainMap = _mapper.Map&lt;TDomainEntity&gt;(dbDataGetId);

        return domainMap;
    }
}

, and then having in the mapping profile configurations for each pair of entities, like UserDbTbl to User.

huangapple
  • 本文由 发表于 2023年3月15日 21:23:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/75745321.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定