英文:
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<T>().ToListAsync()
and then try to map it to generic entity type <T>
- in my code I just map it to IReadOnlyList<T>
. 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<T> where T : class
{
Task<T> GetByIdAsync(int id);
Task<IReadOnlyList<T>> ListAllAsync();
Task<T> AddAsync(T entity);
Task UpdateAsync(T entity);
Task DeleteAsync(T entity);
}
// Interface implementation
public class BaseRepository<T> : IAsyncRepository<T> where T : class
{
protected readonly RegionManagementDbContext _dbContext;
private readonly IMapper _mapper;
public BaseRepository(RegionManagementDbContext dbContext, IMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
}
public async Task<IReadOnlyList<T>> ListAllAsync()
{
var dbDataList = await _dbContext.Set<T>().ToListAsync();
var domainMap = _mapper.Map<IReadOnlyList<T>>(dbDataList);
return domainMap;
}
public async Task<T> AddAsync(T entity)
{
var dbDataAdd = await _dbContext.Set<T>().AddAsync(entity);
var domainMap = _mapper.Map<T>(dbDataAdd);
return domainMap;
}
public virtual async Task<T> GetByIdAsync(int id)
{
var dbDataGetId = await _dbContext.Set<T>().FindAsync(id);
var domainMap = _mapper.Map<T>(dbDataGetId);
return domainMap;
}
public async Task DeleteAsync(T entity)
{
var dbDataDelete = _dbContext.Set<T>().Remove(entity);
await _mapper.Map<T>(dbDataDelete);
}
public async Task UpdateAsync(T entity)
{
var dbDataUpdate = _dbContext.Set<T>().Update(entity);
await _mapper.Map<T>(dbDataUpdate);
}
}
// add mapping profile
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<typeof(IAsyncRepository<>), typeof(BaseRepository<>)>();
}
}
答案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;
}
}
在映射配置中为每一对实体,如 UserDbTbl
到 User
,有这样的部分。
英文:
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<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;
}
}
, and then having in the mapping profile configurations for each pair of entities, like UserDbTbl
to User
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论