Шаблон репозитория и сопоставление между моделями доменов и Entity Framework
Мои репозитории имеют дело с и обеспечивают постоянство для богатой доменной модели. Я не хочу раскрывать анемичные сущности данных Entity Framework моим бизнес-уровням, поэтому мне нужен какой-то способ сопоставления между ними.
В большинстве случаев построение экземпляра модели предметной области из объекта данных требует использования параметризованных конструкторов и методов (поскольку он богат). Это не так просто, как соответствие свойства / поля. AutoMapper может использоваться для противоположной ситуации (сопоставление с объектами данных), но не при создании моделей предметной области.
Ниже приводится ядро моего шаблона хранилища.
EntityFrameworkRepository
Класс работает с двумя универсальными типами:
TDomainModel
: Богатая доменная модельTEntityModel
: Сущность данных Entity FrameworkОпределены два абстрактных метода:
ToDataEntity(TDomainModel)
: Преобразовать в объекты данных (дляAdd()
а такжеUpdate()
методы)ToDomainModel(TEntityModel)
: Построить доменные модели (дляFind()
метод).Конкретные реализации этих методов будут определять отображение, необходимое для рассматриваемого хранилища.
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);
}
Вот базовый пример реализации репозитория:
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
}
}
}
Проблема:
A Company
может состоять из многихDepartments
, Если я хочу загрузить их сCompanyRepository
при полученииCompany
тогда где бы я определил отображение междуDepartment
иDepartmentDataEntity
?
Я мог бы предоставить больше методов отображения вCompanyRepository
, но это скоро станет грязным. Скоро в системе появятся дублированные методы отображения.
Как лучше подходить к вышеуказанной проблеме?