#dependency-injection #domain-driven-design #repository #entity-framework-4.1
#внедрение зависимостей #дизайн, управляемый доменом #репозиторий #entity-framework-4.1
Вопрос:
Я работаю над большим проектом, используя ASP.Net MVC 3, EF 4.1 и Ninject для внедрения зависимостей. Я прочитал многие из существующих здесь вопросов, касающихся DDD, EF и шаблона репозитория, но, похоже, я не могу найти никого, кто включал бы хранимые процедуры с этими шаблонами.
Мне не нравится идея реализации еще одного шаблона репозитория поверх того, что, по-видимому, уже является шаблоном UnitOfWork / RepositoryPattern, уже определенным с помощью DbContext. Кроме того, мне обычно не нравится идея создания классов служб и репозиториев для каждого типа объектов в системе, если это возможно.
Источник моей проблемы связан с этим общим интерфейсом репозитория, который, похоже, используют все.
public interface IRepository<TEntity> where TEntity : class
{
TEntity Get(Expression<Func<TEntity, bool>> whereClause);
IEnumerable<TEntity> List();
IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> whereClause);
void Add(TEntity entity);
void Delete(TEntity entity);
// And so on...
}
Это здорово, если все ваши запросы могут быть в контексте одной сущности. Для меня это прерывается, когда я хочу получить доступ к хранимой процедуре. С помощью EF 4.1 и Code Generatrion вы можете добавить хранимые процедуры (например, SelectUser), и это сгенерирует контекст, который выглядит примерно так.
namespace MyCompany.Data.Database
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
using MyCompany.Domain.Entities;
using MyCompany.Domain.Contracts;
public partial class MyCompanyEntities : DbContext
{
public MyCompanyEntities()
: base("name=MyCompanyEntities")
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public DbSet<Order> Orders { get; set; }
public DbSet<User> Users { get; set; }
public virtual ObjectResult<User> SelectUser(Nullable<int> userId)
{
((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace.LoadFromAssembly(typeof(User).Assembly);
var userIdParameter = userId.HasValue ?
new ObjectParameter("UserId", userId) :
new ObjectParameter("UserId", typeof(int)); MyCompanyEntities x; x.
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<User>("SelectUser", userIdParameter);
}
public virtual ObjectResult<User> SelectUser(Nullable<int> userId, MergeOption mergeOption)
{
((IObjectContextAdapter)this).ObjectContext.MetadataWorkspace.LoadFromAssembly(typeof(User).Assembly);
var userIdParameter = userId.HasValue ?
new ObjectParameter("UserId", userId) :
new ObjectParameter("UserId", typeof(int));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction<User>("SelectUser", mergeOption, userIdParameter);
}
}
}
В рамках моей настройки DDD у меня есть класс UserService, и я хотел бы «внедрить» репозиторий в его конструктор. Многие примеры предполагают, что конструктор должен принимать (IRepository<User> UserRepository) . У меня это не работает. Хранимые процедуры генерируются в классе DbContext как метод, и я не могу его увидеть.
Единственное, что я могу придумать, это либо создать другой интерфейс с методами хранимых процедур на нем. Я действительно не хочу добавлять его в общий IRepository, потому что тогда, когда у вас есть экземпляр IRepository<Order>, вы все равно увидите SelectUser, что кажется немного странным. Может быть, это не имеет большого значения?
Возможно, я иду по этому неправильному пути. Должен ли я не беспокоиться о создании интерфейса поверх моего DbContext, если я не пытаюсь создать совершенно новый шаблон репозитория? Я действительно создавал его для внедрения зависимостей. Было бы неправильно, если бы конструктор UserService использовал экземпляр MyCompanyEntities вместо интерфейса?
Комментарии:
1. В качестве примечания я хотел бы поблагодарить Ладислава Мрнка за сотни ответов, которые он уже дал по смежным темам. Они были безумно полезны!
Ответ №1:
То, что вы нашли, естественно. Проблема в том, что общего репозитория недостаточно для реальных сценариев. Это хорошо только для «базовой» реализации. Вам нужен конкретный репозиторий для объекта User, который будет предоставлять вызов переноса метода в контекстную хранимую процедуру.