Unity Framework - создание и размещение данных в Entity Framework в соответствующее время - PullRequest
6 голосов
/ 13 марта 2010

С любезной помощью StackOverflow у меня есть Unity Framework для создания моих связанных зависимостей, включая объект Entity Framework datacontext:

using (IUnityContainer container = new UnityContainer())
{
    container.RegisterType<IMeterView, Meter>();
    container.RegisterType<IUnitOfWork, CommunergySQLiteEntities>(new ContainerControlledLifetimeManager());
    container.RegisterType<IRepositoryFactory, SQLiteRepositoryFactory>();
    container.RegisterType<IRepositoryFactory, WCFRepositoryFactory>("Uploader");
    container.Configure<InjectedMembers>()
        .ConfigureInjectionFor<CommunergySQLiteEntities>(
            new InjectionConstructor(connectionString));

    MeterPresenter meterPresenter = container.Resolve<MeterPresenter>();

это очень хорошо работает при создании объекта Presenter и отображении связанного с ним представления, я очень рад.

Однако проблема, с которой я сейчас сталкиваюсь, заключается в сроках создания и удаления объекта Entity Framework (и я подозреваю, что это пойдет на любой объект IDisposable). Используя Unity, подобный этому, объект SQL EF «CommunergySQLiteEntities» создается сразу, так как я добавил его интерфейс IUnitOfWork в конструктор MeterPresenter

    public MeterPresenter(IMeterView view, IUnitOfWork unitOfWork, IRepositoryFactory cacheRepository)
    {
        this.mView = view;
        this.unitOfWork = unitOfWork;
        this.cacheRepository = cacheRepository;
        this.Initialize();
    }

В то время я чувствовал себя немного неловко из-за того, что не хочу держать открытым соединение с базой данных, но я не мог найти другого пути с использованием внедрения зависимостей Unity. Конечно же, когда я на самом деле пытаюсь использовать текст данных, я получаю эту ошибку:

    ((System.Data.Objects.ObjectContext)(unitOfWork)).Connection 
  '((System.Data.Objects.ObjectContext)(unitOfWork)).Connection'
threw an exception of type 'System.ObjectDisposedException'
 System.Data.Common.DbConnection {System.ObjectDisposedException}

Мое понимание принципа IoC заключается в том, что вы устанавливаете все свои зависимости наверху, разрешаете свой объект и все, и вы уходите. Тем не менее, в этом случае некоторые дочерние объекты, например, datacontext, не нужно инициализировать во время создания родительского объекта Presenter (как это было бы, передавая их в конструкторе), но Presenter действительно необходимо знать, какой тип использовать для IUnitOfWork, когда он хочет общаться с базой данных.

В идеале, я хочу что-то подобное в моем разрешенном докладчике:

using(IUnitOfWork unitOfWork = new NewInstanceInjectedUnitOfWorkType())
{
    //do unitOfWork stuff
}

Таким образом, докладчик знает, какую реализацию IUnitOfWork следует использовать для непосредственного создания и удаления, предпочтительно из исходного вызова RegisterType. Нужно ли помещать другой контейнер Unity внутри моего Presenter, рискуя создать новую зависимость?

Это, вероятно, действительно очевидно для гуру IoC, но я бы очень оценил указатель в правильном направлении.

Ответы [ 3 ]

4 голосов
/ 13 марта 2010

Вам не нужно беспокоиться об инициализации ObjectContext одновременно с созданием докладчика - ObjectContext не удерживает открытым соединение с базой данных. Скорее, он открывает соединения по мере необходимости, когда ему действительно необходимо связаться с базой данных, т. Е. Когда вы выполняете запрос или фиксируете изменения, и снова закрывает соединение, как только оно закончится. Соединение будет оставаться открытым только в том случае, если вы откроете его явно, что редко встречается в Entity Framework.

Если вы получаете ObjectDisposedException с использованием ContainerControlledLifetimeManager, то это означает, что ваш контейнер утилизируется перед докладчиком, что является ошибкой проектирования. Не совсем понятно, какова ваша среда (ASP.NET? Winforms?), Но ContainerControlledLifetimeManager, вероятно, здесь не подходит, так как он работает как экземпляр Singleton. Обычно вы действительно захотите создать новый экземпляр контекста при разрешении типа - есть много проблем, с которыми вы можете столкнуться, если вместо этого вы используете синглтон.

Итак - я бы избавился от ContainerControlledLifetimeManager здесь, а также убедился, что ваш контейнер не утилизируется слишком рано; тот факт, что он находится в блоке using, указывает на то, что это, вероятно, причина вашего ObjectDisposedException. (Конечно, вам все равно придется в конечном итоге утилизировать контейнер - просто вы, вероятно, делаете что-то вроде создания немодальной формы, которая остается живой еще долго после того, как контроль покидает область действия using).

1 голос
/ 13 марта 2010

Почему бы вам просто не удалить IUnitOfWork из конструктора и вместо этого внедрить контейнер Unity? Таким образом, вы будете иметь возможность вызывать container.Resolve<IUnitOfWork>() в любом месте вашего кода, когда это уместно.

Пример:

using(IUnitOfWork unitOfWork = container.Resolve<IUnitOfWork>()) 
{ 
    //do unitOfWork stuff 
} 

Не забудьте установить время жизни экземпляра на один.

Michael

0 голосов
/ 28 февраля 2014

Я знаю, что этот вопрос старый, но я все же хотел бы дать здесь свои 2 цента.

Вы можете зарегистрировать свою абстракцию UnitOfWork в обычном режиме, но запросите Func<IUnitOfWork> в своем классе вместо экземпляра. На самом деле это замечательная особенность Unity - возможность разрешать делегаты, которые создают ваш объект, вместо того, чтобы сразу получать объект.

Таким образом, вы можете делать, как хотите, то есть контролировать объем единицы работы внутри вашего метода.

Короче говоря:

container.RegisterType<IUnitOfWork, CommunergySQLiteEntities>();

...

public MeterPresenter(IMeterView view, Func<IUnitOfWork> unitOfWorkFactory, IRepositoryFactory cacheRepository)
{
    this.mView = view;
    this.unitOfWorkFactory = unitOfWorkFactory;
    this.cacheRepository = cacheRepository;
    this.Initialize();
}

...

using(IUnitOfWork unitOfWork = unitOfWorkFactory())
{
    //do unitOfWork stuff
}

Я уже использовал это несколько раз, и я лично рекомендую это, поскольку у вас все еще есть полный контроль над всем, включая макетирование для модульного тестирования, и при этом не связываете свой код ни с чем, кроме его зависимостей.

Вы можете создать интерфейс IUnitOfWorkFactory и добавить его, если вам нужна более сложная логика, но в большинстве случаев достаточно делегата Func<T>.

...