Подтвердить что ты не робот

Использование Entity Framework с Castle Windsor

Я использую первый подход Entity Framework для создания модели DbContext/POCO для приложения MVC. Я хочу избежать зависимостей от DbContext в моих контроллерах, чтобы я мог переключиться на другого поставщика непрерывности, как мне нужно (например, для тестирования модулей).

Чтобы сделать это, я хочу использовать контейнер Castle Windsor IoC. Я планирую зарегистрировать DbContext как службу IUnitOfWork и зарегистрировать общий сервис IRepository, реализации которого я буду использовать для доступа и работы с совокупными корнями в модели.

Я новичок в Виндзоре и не смог найти много информации об использовании его с EF, и у меня есть пара вопросов:

  • Это разумный подход, если я хочу отделить EF от приложения?
  • как установить/зарегистрировать службы IUnitOfWork и общие службы IRepository?
4b9b3361

Ответ 1

Итак, некоторые выводы. Я думал, что напишу это на случай, если он будет полезен кому-то другому, пытающемуся использовать / unit test EF, Windsor и MVC вместе.

Прежде всего, поскольку DbContext реализует как шаблоны репозитория, так и единицы работы, вам нужно взглянуть на то, будут ли выполняться эти реализации или вам нужно создать свои собственные.

Я решил создать свой собственный репозиторий, следуя шаблону DDD: по одному для каждого заполнителя. Причины: инкапсулировать код запроса, чтобы он не просочился в уровень приложения и не мог более легко насмехаться при тестировании контроллеров приложений. Я создал общий репозиторий на основе IRepository<TEntity>. Есть много примеров. Я нашел это хорошим: http://architects.dzone.com/articles/implementing-repository

С другой стороны, я решил отказаться от службы IUnitOfWork, выбрав вместо нее реализацию по умолчанию. Тем не менее, я создал абстракцию IDbContext (не знаю, почему Microsoft не делала этого сама), поэтому я мог издеваться над DbContext при тестировании сервисов репозитория.

Я дал IDbContext только члены DbContext, которые я хотел использовать в репозитории. Итак:

public interface IDbContext: IDisposable
{
    Database Database { get; }
    DbEntityEntry Entry(object entity);
    IDbSet<TEntity> Set<TEntity>() where TEntity : class;
    int SaveChanges();
}

Затем я создал средство и установщик Windsor для своих служб IDbContext и IRepository:

public class EntityFrameworkFacility: AbstractFacility
{
    protected override void Init()
    {
        Kernel.Register(Component.For<IDbContext>()
                                 .ImplementedBy<MyEntities>()
                                 .LifestylePerWebRequest(),
                        Component.For(typeof(IRepository<>))
                                 .ImplementedBy(typeof(Repository<>))
                                 .LifestylePerWebRequest());
    }
}

public class PersistenceInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.AddFacility<EntityFrameworkFacility>();
    }
}

Последняя часть должна была расширить класс контекста Entity Framework для реализации IDbContext и затенять метод Set() для возврата IDbSet, а не DbSet:

public partial class MyEntities : IDbContext
{
    public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
    {
        return base.Set<TEntity>();
    }
}

При наличии всего этого (и регистрации ControllerFactory, показанной в документах Windsor) становится тривиальным, чтобы заставить Windsor вводить объекты IRepository (или IDbContext) в конструкторы контроллера, если требуется:

public ControllerBase(IRepository<Contact> repo)
{
    _repo = repo;
}

В модульных тестах репозитория реальный экземпляр репозитория может быть скопирован с помощью макета IDbContext:

mocks = new MockRepository();
context = mocks.StrictMock<IDbContext>();
repo = new Repository<Contact>(context);

В тестах модуля контроллера можно использовать макетный репозиторий:

mocks = new MockRepository();
repo = mocks.StrictMock<IRepository<Contact>>();
ContactController controller = new ContactController(repo);