Я достиг этого с EF 5.0. Решение слишком сложное, чтобы оставлять сообщения. Я могу дать описание очень высокого уровня.
Базовый класс для хранилища выглядит так ...
public class GenericRepository<TEntityInterface, TEntity>
where TDataInterface : TEntityInterface
where TEntity : class, IBaseEntityInterface, new()
Подкласс этого хранилища будет выглядеть как ...
public class EmployeeRepository<TEntity> : GenericRepository<IEmployeeEntity, TEntity>, IEmployeeRepository
where TEntity : class, IEmployeeEntity, new()
Я использую Шаблоны T4 , чтобы настроить генерацию сущностей для наследования интерфейсов сущностей, или же вы можете создать частичные классы для каждой сущности EF для наследования интерфейсов. Я использовал сценарии code gen для создания интерфейсов для сущностей, которые соотносятся со свойствами сущностей. Все объекты наследуют IBaseEntityInterface.
В какой-то момент в вашем коде (в моем случае, с использованием инфраструктуры инъекций INject) вы объединяете сущность EF с репозиторием, как это ....
Bind<IEmployeeRepository>().To<EmployeeRepository<EmployeeEntity>();
Где EmployeeEntity создается структурой сущности.
Существует проблема с этим подходом: структура сущностей не любит объединения LINQ между интерфейсами сущностей, что может привести к ошибке в зависимости от структуры запроса.
Вы должны выполнять запросы в хранилище к TEntity. Вы можете использовать свойства навигации на интерфейсах сущностей (и на TEntity в репозитории), чтобы эффективно выполнять объединения A-OK.
Однако иногда вам захочется выполнять объединения без навигационных свойств, а обходной путь заключается в предоставлении методов в репозиториях, которые возвращают примитивные объекты IQueryable для использования в других репозиториях, например, запрос идентификаторов, таких как IQueryable или коды IQueryable, создавая в хранилище для другого хранилища, чтобы включить их в запрос.
Я думаю, что в целом в большой кодовой базе преимущества использования интерфейсов объектов вместо прямой ссылки на классы объектов EF перевешивают проблемы, с которыми вы столкнетесь при использовании EF с интерфейсами объектов. Помимо слабой связи, устойчивости к изменениям и т. Д., Вы можете поместить много кода в базовый репозиторий и запрограммировать его на TEntity со свойствами в интерфейсе базового объекта.
например, метод для получения коллекции интерфейсов сущностей, соответствующих предикату с несколькими предварительно загруженными свойствами
public IList<TEntityInterface> Where(Expression<Func<TEntityInterface, bool>> predicate, params string[] includedProperties)
{
DbQuery<TEntity> query = Context.Set<TEntity>();
foreach (string prop in includedProperties)
query = query.Include(prop);
return query.Where(predicate).ToList<TEntityInterface>();
}
Что касается меня, то ссылка на сущности Entity Framework в вашем коде в основном тесно связывает код с EDMX и, следовательно, с конкретной схемой базы данных. Если вам нужно поддерживать несколько схем баз данных с одной и той же кодовой базой, Entity Framework из коробки оставляет вас довольно высокими и сухими.
Надеемся, что в будущей версии EF эти проблемы будут решены, и мы все сможем стать хорошими маленькими программистами и использовать интерфейсы вместо классов EF без этих хитростей.