Wzorzec repozytorium i mapowanie między modelami domeny a ramą Entity Framework
Moje repozytoria radzą sobie i zapewniają trwałość dla modelu bogatej domeny. Nie chcę ujawniać anemicznej, encji Framework jednostki danych do moich warstw biznesowych, więc potrzebuję jakiegoś sposobu mapowania między nimi.
W większości przypadków skonstruowanie instancji modelu domeny z jednostki danych wymaga użycia sparametryzowanych konstruktorów i metod (ponieważ jest bogata). To nie jest tak proste, jak dopasowanie własności / pola. AutoMapper może być użyty w sytuacji odwrotnej (mapowanie do jednostek danych), ale nie podczas tworzenia modeli domeny.
Poniżej znajduje się rdzeń mojego wzorca repozytorium.
TheEntityFrameworkRepository
klasa działa z dwoma rodzajami rodzajowymi:
TDomainModel
: Model bogatej domenyTEntityModel
: Jednostka danych Entity FrameworkZdefiniowano dwie abstrakcyjne metody:
ToDataEntity(TDomainModel)
: Aby przekonwertować na jednostki danych (dlaAdd()
iUpdate()
metody)ToDomainModel(TEntityModel)
: Aby skonstruować modele domen (dlaFind()
metoda).Konkretne implementacje tych metod definiują mapowanie wymagane dla danego repozytorium.
public interface IRepository<T> where T : DomainModel
{
T Find(int id);
void Add(T item);
void Update(T item);
}
public abstract class EntityFrameworkRepository<TDomainModel, TEntityModel> : IRepository<TDomainModel>
where TDomainModel : DomainModel
where TEntityModel : EntityModel
{
public EntityFrameworkRepository(IUnitOfWork unitOfWork)
{
// ...
}
public virtual TDomainModel Find(int id)
{
var entity = context.Set<TEntityModel>().Find(id);
return ToDomainModel(entity);
}
public virtual void Add(TDomainModel item)
{
context.Set<TEntityModel>().Add(ToDataEntity(item));
}
public virtual void Update(TDomainModel item)
{
var entity = ToDataEntity(item);
DbEntityEntry dbEntityEntry = context.Entry<TEntityModel>(entity);
if (dbEntityEntry.State == EntityState.Detached)
{
context.Set<TEntityModel>().Attach(entity);
dbEntityEntry.State = EntityState.Modified;
}
}
protected abstract TEntityModel ToDataEntity(TDomainModel domainModel);
protected abstract TDomainModel ToDomainModel(TEntityModel dataEntity);
}
Oto podstawowy przykład implementacji repozytorium:
public interface ICompanyRepository : IRepository<Company>
{
// Any specific methods could be included here
}
public class CompanyRepository : EntityFrameworkRepository<Company, CompanyTableEntity>, ICompanyRepository
{
protected CompanyTableEntity ToDataEntity(Company domainModel)
{
return new CompanyTable()
{
Name = domainModel.Name,
City = domainModel.City
IsActive = domainModel.IsActive
};
}
protected Company ToDomainModel(CompanyTableEntity dataEntity)
{
return new Company(dataEntity.Name, dataEntity.IsActive)
{
City = dataEntity.City
}
}
}
Problem:
A Company
może składać się z wieluDepartments
. Jeśli chcę chętnie załadować te zCompanyRepository
przy pobieraniu aCompany
to gdzie zdefiniowałbym mapowanie między aDepartment
i aDepartmentDataEntity
?
Mogę podać więcej metod mapowania wCompanyRepository
, ale wkrótce stanie się bałagan. Wkrótce w systemie powielone zostaną metody mapowania.
Jakie jest lepsze podejście do powyższego problemu?