DbContextFactory в проекте WPF .Net 6 (EF, MVVM)

Мое приложение работает нормально, когда я использую простую/классическую реализацию DBContext, но когда я пытаюсь DbContextFactory, _contextFactory.CreateDbContext() всегда терпит неудачу с «нулевым» исключением. Что мне не хватает?

Мой App.xaml.cs (при использовании DBContext никаких изменений в этом файле не требовалось):

private void ConfigureServices(IServiceCollection services)
{
    string defaultConnection = Settings.Default.DefaultConnection;

    services.AddDbContextFactory<MyDbContext>(options => options.UseMySql(defaultConnection, ServerVersion.AutoDetect(defaultConnection)));

    services.AddTransient(typeof(MainWindow));
}

MyDbContext.cs файл (никаких изменений не потребовалось, так как он уже соответствует требованиям DbContextFactory конструктора):

public class MyDbContext : DbContext
{
    public MyDbContext (DbContextOptions<MyDbContext> options)
        : base(options)
    {
    }
    
    // DbSets 

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            string defaultConnection = Settings.Default.DefaultConnection;

            var options = new DbContextOptionsBuilder<MyDbContext>()
                            .UseMySql(defaultConnection, ServerVersion.AutoDetect(defaultConnection))
                            .Options;
        }

        optionsBuilder.UseLazyLoadingProxies();
        // To be disabled in production 
        optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);
        optionsBuilder.EnableSensitiveDataLogging();
        optionsBuilder.EnableDetailedErrors();
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Table building logic for EF code-first
    }
}

MainWindow.xaml.cs файл:

public partial class MainWindow : Window
{
    private readonly IDbContextFactory<MyDbContext> _contextFactory;

    private SomeVieModel _someVieModel;

    public MainWindow()
    {
        InitializeComponent();

        var _context = _contextFactory.CreateDbContext(); // Throws 'null' exception

        // Probably should be instantiating a new DbContext 
        // in the VM itself, instead of passing it on? 
        _someVieModel = new SomeVieModel(_context); 
    }
}

Я проверил множество примеров Blazor из-за отсутствия примеров WPF, и я чувствую, что упускаю что-то очень простое, какую-то одну строку DbContextFactory экземпляра объекта? Как в этом примере - откуда берется IDbContextFactory<MyDbContext> contextFactory объект и где он создается? Спасибо!

Ошибка заключалась в том, что вы не внедрили IDbContextFactory<MyDbContext> в конструктор MainWindow. Вот почему фабрика так и не была создана, а вы получили NullReferenceException. Все остальное выглядит нормально - может быть, за исключением того, что что-то вводится в окно, которое затем просто передает его в модель представления вместо того, чтобы вводить вещи туда, где они нужны. Но это касается дизайна, а не ошибки, которую вы получили.

Jürgen Röhr 15.10.2022 20:52

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

Donatas 15.10.2022 20:58
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
101
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я думаю, что у меня это получилось, хотя я уверен, что некоторые из вас укажут на ошибку моего пути :)

Я только что понял, что у меня уже есть собственный класс DbContextFactory, созданный для миграции базы данных, потому что иначе EF Core не смог бы подключиться к базе данных только через класс DbContext проекта.

public class MyDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
    public MyDbContext CreateDbContext(string[]? args = null)
    {
        string defaultConnection = Settings.Default.DefaultConnection;

        var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
        optionsBuilder.UseMySql(defaultConnection, ServerVersion.AutoDetect(defaultConnection));

        return new MyDbContext(optionsBuilder.Options);
    }
}

Я прокомментировал код в App.xaml.cs out и инициализировал DbContextFactory через свой собственный класс вместо IDbContextFactory интерфейса:

public partial class MainWindow : Window
{
    private readonly MyDbContextFactory  _contextFactory;

    private SomeVieModel _someVieModel;

    public MainWindow()
    {
        InitializeComponent();

        _contextFactory = new MyDbContextFactory();

        _someVieModel = new SomeVieModel(_contextFactory); 
    }
}

И вызвал CreateDbContext() в модели представления:

public class SomeVieModel : ViewModelBase
{
    private readonly MyDbContextFactory _contextFactory;

    public SomeVieModel(MyDbContextFactory contextFactory)
    {
        _contextFactory = contextFactory; 
        
        await LoadDBStuff();
    }
    
    private async Task LoadDBStuff()
    {
        using (var context = _contextFactory.CreateDbContext())
        {
            await context.SomeDataModel.LoadAsync();
            SomeDataModelObservableCollection = context.SomeDataModel.Local.ToObservableCollection();
        }
    }
}

Другие вопросы по теме