1

I recently upgraded my app to .net core 6 and now I am getting this error on this.ChangeTracker in my code:

public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
        _options = options;
        this.ChangeTracker.LazyLoadingEnabled = false;
        this.ChangeTracker.AutoDetectChangesEnabled = true;
    }

Before erroring it was performing dependency injection

IUnityContainer container = HangfireUnityConfig.GetConfiguredContainer();
var userService = container.Resolve<IUserService>();

This is the line of code where I AddDBContext with the connection string.

var connectionString = builder.Configuration.GetConnectionString("ConnectionString");

builder.Services.AddDbContext<ApplicationDbContext>(x => x.UseSqlServer(connectionString));

builder.Services.AddDatabaseDeveloperPageExceptionFilter();

Full error message: System.InvalidOperationException

  HResult=0x80131509
  Message=No database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider. If 'AddDbContext' is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
  Source=Microsoft.EntityFrameworkCore
  StackTrace:
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider scopedProvider, DbContextOptions contextOptions, DbContext context)
   at Microsoft.EntityFrameworkCore.DbContext.get_ContextServices()
   at Microsoft.EntityFrameworkCore.DbContext.get_ChangeTracker()
   at MyApp.Data.ApplicationDbContext..ctor(DbContextOptions`1 options) in C:\MyApp\Data\ApplicationDbContext.cs:line 34

Any ideas how to solve this?

Update

I added the OnConfiguring() method to my ApplicationDbContext and now get a new error when trying to cast to IObjectContextAdapter.

The error says System.InvalidCastException: Unable to cast object of type 'MyApp.Data.ApplicationDbContext' to type 'System.Data.Entity.Infrastructure.IObjectContextAdapter'.

This is the code it breaks on

public List<KeyValuePair<string, long>> GetKeys(EntityEntry entry)
        {
            var keys = new List<KeyValuePair<string, long>>();
            var objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(entry.Entity);

            if (objectStateEntry.EntityKey.EntityKeyValues != null)
            {
                keys.AddRange(objectStateEntry.EntityKey.EntityKeyValues.Select(key => new KeyValuePair<string, long>(key.Key, Convert.ToInt64(key.Value))));
            }

            return keys;
        }

This is what my OnConfiguring() method looks like

 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                optionsBuilder.UseSqlServer("myconnectionstring");
            }
        }
jonv562
  • 293
  • 1
  • 4
  • 23
  • If this was working before your upgrade to .NET 6 (they dropped Core from the name), ... did you follow the migration guidance from Microsoft? For example, at https://learn.microsoft.com/en-us/aspnet/core/migration/31-to-60. Otherwise ... where are you providing the data source (connection string) to EF? – Scott Hoffman Feb 01 '23 at 16:07
  • @ScottHoffman Ive added the code where I provide the connection string – jonv562 Feb 01 '23 at 16:25
  • Don't change configuration options through the `ChangeTracker` instance *in the constructor*. That's what the error complains about. You can't have a ChangeTracker without a fully constructed DbContext. – Panagiotis Kanavos Feb 01 '23 at 16:25
  • 1
    Put `ChangeTracker.LazyLoadingEnabled = false;` in `OnConfiguring`. The constructor must finish before any other method can be called. That includes the call to `OnConfiguring`. `ChangeTracker.AutoDetectChangesEnabled` is true by default and doesn't have to change – Panagiotis Kanavos Feb 01 '23 at 16:30
  • Even `LazyLoadingEnabled` can be omitted. As [the property docs explain](https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.changetracking.changetracker.lazyloadingenabled?view=efcore-7.0) `lazy loading will only occur for navigation properties of entities that have also been configured in the model for lazy loading.` – Panagiotis Kanavos Feb 01 '23 at 16:31
  • @PanagiotisKanavos i tried omitting the ChangeTracker lines and still got the error but in a different part of my code. I updated my post with the code snippet where it breaks – jonv562 Feb 01 '23 at 17:03
  • That code uses a custom `IDataContextAsync` property, not a DbContext. I have no idea what `IDataContextAsync` is but I do know that a DbContext already is a high-level multi-entity Repository and Unit of Work, it doesn't need to be wrapped in a low-level single-entity DAO. Nor does it need an extra Unit-of-Work implementation. The current one works just fine: Call `SaveChanges` to commit all pending changes, let the DbContext get disposed to discard them. Nothing else is needed – Panagiotis Kanavos Feb 01 '23 at 17:06
  • If you want to unit test your application you can configure your DbContexts to use the in-memory provider or SQLite in in-memory mode. Or you can create *real* domain repositories (this one isn't), that load an entire graph of objects at a time suitable for the specific domain/use case, without exposing the underlying implementation. – Panagiotis Kanavos Feb 01 '23 at 17:08
  • For example, in an e-Shop scenario, a good repository class wouldn't have generic Load or Update methods for individual entities. It would have eg a method `LoadCart(CustomerId)` or `LoadCart(Customer)` that would load the cart, all products, their details, delivery options etc, everything needed to fulfill the Cart use case. In that case, instead of trying to mock DbContext you'd create a fake `ICartRepository` whose `LoadCart` would return your own mock objects. Instead `Update` or `Save` methods, it would have meaningful methods like `Checkout` or `ApplyCoupon` etc – Panagiotis Kanavos Feb 01 '23 at 17:15

0 Answers0