Доступ к хранимым процедурам в сгенерированном в коде DbContext с помощью Entity Framework 4.1 с помощью DDD

#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, который будет предоставлять вызов переноса метода в контекстную хранимую процедуру.