Введенная зависимость DbContext пуста после заполнения DbContext, созданного с помощью new (EF7, ASP.NET 5, vnext)

Я относительно новичок в EF7 и слышал, что внедрение зависимостей DbContexts в конструктор контроллера - хороший способ получить DbContext для использования в заданных методах действия. Однако есть много ситуаций, когда внедрение зависимостей невозможно (например, доступ к базе данных в обычных классах), и необходимо использовать шаблон using(VectorDbContext dbContext...).

Я столкнулся с проблемой, когда добавление данных в DbContext, созданное с помощью шаблона using, не может быть доступно контексту, в который была введена зависимость. DbContext - это простая база данных InMemory, используемая для тестирования - она ​​ни к чему не подключается.

Вот код, который добавляет сущности в DbContext, для тестирования я вызываю это в Startup.cs:

using (ExampleDbContext dbContext= new ExampleDbContext()) {
    dbContext.Things.Add(
        new Thing() {
            Stuff= "something"
        });

    dbContext.SaveChanges();
}

Вот код доступа в контроллере:

public class ExampleController : Controller {
    public ExampleController(ExampleDbContext exampleDbContext) {
        this.ExampleDbContext= exampleDbContext;
    }

    public ExampleDbContext ExampleDbContext { get; set; }

    public async Task<IActionResult> ExampleAction() {

        // new DbContext:
        using(ExampleDbContext dbContext = new ExampleDbContext ()) {
            var List1 = (await dbContext.Things
                .AsNoTracking()
                .ToListAsync());
        }

        // Injected DbContext:
        var List2 = (await this.ExampleDbContext.Things
            .AsNoTracking()
            .ToListAsync());
    }
}

При пошаговом прохождении List1 содержит ожидаемый один элемент, но List2 всегда пуст!

Что я делаю неправильно? Похоже, что DbContexts каким-то образом не синхронизируются, как инъекция зависимостей создает DbContext / откуда он?

РЕДАКТИРОВАТЬ: Я только что провел дополнительное тестирование и подтвердил, что любые объекты, добавленные в DbContext, созданные с помощью new, видны только в new, а объекты, добавленные в Injected DbContext, видны только внутри Injected DbContext, что заставляет меня поверить, что они подключаются к разным базам данных, но я не могу подтвердить.


person Ryan    schedule 29.01.2015    source источник
comment
Что касается того, где происходит инъекция DbContext: я реализовал SimpleInjector, чтобы сделать это за меня, следуя нашему уважаемому S.O. член Стивен и его блог о том, как это реализовать. Я нашел его подход очень полезным, может быть, вы сможете решить, как решить вашу проблему с помощью его пошагового руководства!   -  person Allmighty    schedule 29.01.2015
comment
В настоящее время я использую MVC6, встроенный в Dependency Injector, по-видимому, он создает объекты для каждой области запроса , как описано здесь, и удаляет их впоследствии. Понятия не имею, почему один и тот же DbContext представляет два разных представления данных. Спасибо за ссылку в блоге, я мог бы реализовать это для более точного контроля.   -  person Ryan    schedule 29.01.2015
comment
@Ryan - Это не тот же DbContext. Вы создали новый. Это два отдельных DbContexts, поэтому, конечно, они содержат разные наборы данных в своих внутренних кэшах. Понятия не имею, зачем вы создаете новый экземпляр ..   -  person Erik Funkenbusch    schedule 29.01.2015
comment
@Ryan - также вы ошибаетесь на 100% (ну да ладно, ошибаетесь на 99,9%) в том, что во многих ситуациях внедрение зависимостей невозможно. Вы просто не понимаете, как внедрять зависимости и как правильно ее использовать.   -  person Erik Funkenbusch    schedule 29.01.2015
comment
@ErikFunkenbusch Извините, это два разных экземпляра DbContext, однако они все равно должны предоставлять доступ к одной и той же резервной базе данных и, следовательно, содержать одни и те же данные при создании, учитывая, что данные были добавлены до создания любого из них. Кеш тут не причем? Кроме того, мне нужен доступ к DbContext в настраиваемом IRouteConstraint, который я создаю явно в ConfigureServices при запуске. Учитывая, что EF не может (по умолчанию) внедрять зависимости в методы, а только в конструкторы, я не могу использовать поставщика внедрения зависимостей для получения нового контекста DbContext.   -  person Ryan    schedule 29.01.2015
comment
@ErikFunkenbusch Я согласен с вами насчет двух отдельных DbContext, но разве каждый из них не должен выходить за пределы своего внутреннего кеша и напрямую запрашивать базу данных и, следовательно, возвращать одни и те же данные?   -  person Sergey Kolodiy    schedule 29.01.2015
comment
@Ryan - Опять же, вам не хватает понимания того, как использовать инъекцию зависимостей, и вы утверждаете, что не можете сделать то или это, в то время как на самом деле вы имеете в виду, что я не понимаю, как это сделать. Во-первых, я бы предположил, что необходимость доступа к DbContext в RouteConstraint - это очень плохая конструкция и нарушает принцип единой ответственности. Вы не объяснили, зачем вам это нужно, поэтому я не могу предложить лучшего решения. Я предполагаю, что вы либо пытаетесь реализовать какую-то мультиарендность, либо пытаетесь реализовать какую-то маршрутизацию на основе ролей. Однако обычно вместо этого вы вводите фабрику   -  person Erik Funkenbusch    schedule 29.01.2015
comment
@Sergey - Это зависит от того, он не показал свою конфигурацию DI, поэтому мы не знаем, как регистрируются его зависимости.   -  person Erik Funkenbusch    schedule 29.01.2015
comment
@Sergey - Кроме того, я считаю, что InMemoryStore предназначен для модульного тестирования и, как таковой, хранит свою собственную базу данных в памяти для каждого контекста, которая также удаляется при удалении контекста. Хотя я могу ошибаться в этом.   -  person Erik Funkenbusch    schedule 29.01.2015
comment
@ErikFunkenbusch Я намерен сделать что-то вроде маршрутизации на основе ролей, у меня действительно есть вопрос по этой части моего проекта здесь. Что касается конфигурации DI, я использую контейнер DI по умолчанию, предоставленный в vnext, как указано здесь, я не уверен, как это настроено - на данном этапе, похоже, очень мало документации.   -  person Ryan    schedule 29.01.2015
comment
@Ryan - Я сделаю несколько предложений через несколько часов, когда у меня будет время. на самом деле это не сложная проблема.   -  person Erik Funkenbusch    schedule 29.01.2015
comment
@ErikFunkenbusch Большое спасибо!   -  person Ryan    schedule 29.01.2015


Ответы (1)


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

Это пример конфигурации Unity, в которой явно указан параметр конструктора:

<register type="DbContext, [assembly-name]" mapTo="DbContext, [assembly-name]">
<constructor>
    <param name="nameOrConnectionString" value="Test"/>
</constructor>
</register>

Поэтому я бы проверил конфигурацию вашего контейнера.

person Sergey Kolodiy    schedule 29.01.2015
comment
Это определенная возможность - я знаю, что это определенно происходит, когда методы расширения без параметров используются в DbContext OnConfiguring для настройки соединения. Раньше я работал над этим, вручную вводя строку подключения, то есть options.UseSqlServer(Configuration.Get("Data:DefaultConnection:ConnectionString"));, а не options.UseSqlServer(). Однако кажется, что UseInMemoryStore() не имеет параметризованных перегрузок, поэтому я ничего не могу с этим поделать ... Я собираюсь покопаться в исходном коде vNext. - person Ryan; 29.01.2015