My application is working fine when I use a plain/classic DBContext
implementation, but when I try DbContextFactory
, _contextFactory.CreateDbContext()
is always failing with 'null' exception. What am I missing?
My App.xaml.cs
(no changes were needed in this file whilst using 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
file (no changes were needed as it seems to match DbContextFactory
constructor's requirements already):
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
file:
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);
}
}
I've checked numerous Blazor examples, because of the lack of WPF ones, and I feel I'm missing something very simple, some one line of DbContextFactory
object instantiation? Like in this example - where is IDbContextFactory<MyDbContext> contextFactory
object coming from and where is it instantiated? Thank you!
CodePudding user response:
I think I've worked it out, although I'm sure some of you will be pointing out the error of my ways :)
I just realised, that I've already had my own DbContextFactory
class created for database migrations, because otherwise the EF Core could not connect to the database via project's DbContext
class alone.
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);
}
}
I've commented the code in App.xaml.cs
out and initialised DbContextFactory
via my own class instead of IDbContextFactory
interface:
public partial class MainWindow : Window
{
private readonly MyDbContextFactory _contextFactory;
private SomeVieModel _someVieModel;
public MainWindow()
{
InitializeComponent();
_contextFactory = new MyDbContextFactory();
_someVieModel = new SomeVieModel(_contextFactory);
}
}
And called CreateDbContext()
in a view model:
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();
}
}
}