Entity Framework 4.1 Единица работы по внедрению первой зависимости в базу данных

Хорошо, есть масса примеров использования единицы работы с внедрением зависимостей для Code First, использование универсальных репозиториев и все такое прочее.

Есть ли у кого-нибудь пример, делающий это с помощью Database First (edmx с генератором dbContext Generator (T4)), хранимых процедур как импорта функций, единицы работы с внедрением зависимостей.




Ответы (1)


Контекст для code first или dbfirst будет одинаковым (DbContext).

Хранимые процедуры отображаются в вашем репозитории вместо вызова context.Customers, который вы вызываете context.Database.Query("Proc_whatever").

Есть ли конкретное место, в котором вам нужна помощь, у меня может быть образец кода для него, но все вышеперечисленное делается так же, как di, code first, общие репозитории и т. д. Единственное изменение для реализации UnitOfWork — это убедиться, что ваш репозитории не вызывают SaveChanges, в вашем интерфейсе UnitOfWork есть метод Save(), который, в свою очередь, вызывает сохранение изменений.

Я обновлю код на https://github.com/adamtuliper/EF5-for-Real-Web-Applications, чтобы включить единицу работы. Однако мне не нравится реализация, что-то кажется неправильным, и, таким образом, я больше склоняюсь к CQRS.

Итак, идея здесь такова: Inject IUnitOfWork IUnitOfWork содержит IContext, который также внедряется и отображается в Context. IUnitOfWork сопоставляется с конкретной реализацией UnitOfWork. Конкретная реализация UnitOfWork ссылается на репозитории:

Это частично не приходит мне в голову, так что извините за ошибки компиляции, в принципе это показать


public class YourContext : DbContext, IContext
{
   //just a regular DbContext class except use IDbSet
   public IDbSet Customers { get; set; }
}

public interface IUnitOfWork
{
     ICustomerRepository CustomerRepository { get; }
     IOrderRepository OrderRepository { get; }
     void Save();
}


 public class UnitOfWork : IUnitOfWork, IDisposable
 {
        private readonly IContext _context;
        private ICustomerRepository _customerRepository;
        private IOrderRepository _orderRepository;
        private bool _disposed = false;

        public UnitOfWork(IContext context)
        {
            _context = context;
        }

        public ICustomerRepository CustomerRepository
        {
            get
            {
                if (this._customerRepository == null)
                {
                    this._customerRepository = new CustomerRepository(_context);
                }
                return _customerRepository;
            }
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!this._disposed)
            {
                if (disposing)
                {
                    ((IDisposable)_context).Dispose();
                }
            }
            this._disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

public class CustomerController : Controller
{
   private readonly IUnitOfWork _unitOfWork;
   public CustomerController(IUnitOfWork unitOfWork)
   {
      _unitOfWork = unitOfWork;
   }

   [AutoMap(typeof(Customer), typeof(CustomerIndexViewModel)]
   public ActionResult Index()
   {
        return _unitOfWork.CustomersRepository.GetAll();
        //or if not using AutoMapper, use the viewmodel directly:
        //return _unitOfWork.CustomersRepository.GetAll().Select(c => new CustomerIndexViewModel
                                                    {
                                                        CustomerId = c.CustomerId,
                                                        Address = c.Address,
                                                        City = c.City,
                                                        State = c.State,
                                                        FirstName = c.FirstName,
                                                        LastName = c.LastName
                                                    }).ToArray(); ;
   }
}

Чтобы использовать процедуру, в CustomerRepository вы должны сделать следующее:


public Customer GetById(int id)
{
      return this.Context.Database.SqlQuery("Proc_GetCustomer @customerID", new SqlParameter("@customerID", id)).Single();
      //instead of:  return this.Context.Customers.Include(o => o.Orders).Single(o => o.CustomerId == id);
}

person Adam Tuliper - MSFT    schedule 31.10.2012
comment
Большое вам спасибо, Адам, на самом деле вчера я читал ваш блог, и ваша реализация кажется лучшей из всех, что я видел, поэтому я так рад, что вы ответили на вопрос. Моя цель состоит в том, чтобы иметь возможность делиться контекстом между репозиторием, внедрять репозиторий в сервисный уровень, внедрять сервисный уровень в контроллеры и иметь возможность выполнять модульное тестирование. DOD разрешает только хранимые процедуры, поэтому кажется, что это делает их намного более сложными и трудными для понимания. - person Fab; 01.11.2012
comment
@Adam Tuliper В этой реализации, как бы вы могли внедрить зависимость ICustomerRepository в UnitOfWork ? Разве установка CustomerRepository в качестве свойства внутри UoW не мешает нам внедрить эту зависимость? Спасибо. - person Mohammad Sepahvand; 16.01.2013
comment
Каждый раз, когда вы добавляете новый репозиторий в свою систему, вы должны изменить свой класс UnitOfWork. Меня не устраивает такой подход. - person Usman Khalid; 12.07.2013
comment
@UsmanKhalid, возможно, вы могли бы еще больше упростить с помощью дженериков и т. Д., Но тогда я чувствую, что это хак, чтобы обойти написание небольшого фрагмента кода. Вы можете сократить это до двух строк на репозиторий, и если это проблема, я должен спросить, почему. Если у вас их много и добавить это проблематично, просто создайте шаблон кода (.tt/t4 и т. д.), чтобы сгенерировать его для вас. Здесь можно использовать общий репозиторий с коллекцией в единице рабочего объекта, но многим не нравится подход с универсальным репозиторием, а некоторым нравится. Если вы не возражаете против универсального репозитория, вы можете немного упростить его. - person Adam Tuliper - MSFT; 14.07.2013
comment
@AdamTuliper Я не говорю об универсальном репозитории. Я говорю, что в этом подходе класс UnitOfWork действует как контейнер репозиториев. Поэтому каждый раз, когда вам нужно добавить новый репозиторий в вашу систему, вам также необходимо изменить свой класс UnitOfWork. Мне понравился подход, указанный в этой ссылке: codeproject.com/Articles/543810/ - person Usman Khalid; 14.07.2013
comment
Я говорил о способе упростить вышеизложенное с помощью универсального репозитория. Ссылка, которую вы разместили, является не чем иным, как оболочкой транзакции. Для меня это не шаблон единицы работы, это большая оболочка транзакции. Это приводит к длительным транзакциям и ряду других архитектурных проблем. См. определение единицы работы: martinfowler.com/eaaCatalog/unitOfWork.html. - person Adam Tuliper - MSFT; 16.07.2013