英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论