Using DbPooling ignoresAutoTransactionBehavior flag

I’m using the newest EF core library (8.2.3) and when i’m working locally i’m turning off the transactions (since running cluster locally is a bit of a chore).

I’m using Database.AutoTransactionBehavior = AutoTransactionBehavior.Never; flag for that, and it works like expected.

Lately i turned on context pooling AddDbContextPool and i see that whenever i try to do more than one thing with single DbContext instance i have this exception:

The MongoDB EF Core Provider now uses transactions to ensure all updates in a SaveChanges operation are applied together or not at all. Your current MongoDB server configuration does not support transactions and you should consider switching to a replica set or load balanced configuration. If you are sure you do not need save consistency or optimistic concurrency you can disable transactions by setting 'Database.AutoTransactionBehavior = AutoTransactionBehavior.Never' on your DbContext.

I’ve made sure that the behavior is indeed set to Never. Is that behavior expected? Is it a bug of MongoDB adapter or maybe EF itself?

Hi Jakub.

Where are you setting the Database.AutoTransactionBehavior to Never?

I can repro the exception without setting AutoTransactionBehavior to Never but if I add the Database.AutoTransactionBehavior = AutoTransactionBehavior.Never to my Context’s OnModelCreating (or anywhere that will run after the constructor but before a savechanges) then the error goes away. I think you have to set it for each instance as when the instance is returned to the pool EF resets a bunch of things - possibly including the auto transaction behavior.

Additionally FWIW you don’t need to run an actual cluster to locally support transactions during development. You can simply convert your single standalone into a “replication set” and not add any other nodes. It’s how I normally run the local tests/development here. It basically involves:

  1. Shut down your MongoDB
  2. Modify your shortcut/script to add --replSet "rs0" to the command (see below for services)
  3. Restart MongoDB
  4. Start your MongoDB as normal
  5. Open up a command window using Compass or something similar
  6. Type rs.initiate()

If you’re running MongoDB as a service you’ll need to edit the mongod.conf file normally found in /etc/ with this yaml block instead of modifying the command-line args:

replication:
  replSetName: "rs0"

We are using aspire for local development, i think for now we will need to build custom mongodb Dockerfile to support that, but it should be doable.

For the flag, we are setting it in the OnModelCreating. And i don’t think this is the issue, because turning off db context pooling makes it all work correctly, so it has to be connected to the pooling itself. I’ll try to create some repro project, i’ve encountered that in 2 of our bigger integration tests, maybe there’s something additional there…

I tried OnConfigure, OnModelCreating - no luck. Overriding SaveChanges helped though

Okay, just fixed my test and I’m now correctly getting new contexts from the pool.

If I set it in:

  • The constructor I get a virtual member warning but it works just fine
  • OnConfiguring it works just fine
  • OnModelCreating it fails on the second instance

Are you sure you’re getting the exception with it set on OnConfiguring?

Also are you setting the transaction behavior to anything else anywhere?

Yes, it fails on the second instance when i do it in OnConfiguring. We never changed transaction behavior anywhere other setting it to never in that callback.

I had to back off using pooled context anyway, since we are using scoped dependency in interceptor and there is no clear way to workaround this

I have now been able to reproduce this with OnConfiguring - and it makes sense given the way EF rents the contexts after calling the constructor/activator - but setting it in the constructor seems solid and hasn’t reproed for me.

Thanks for the info, we plan to go back to pooling later on, but we have to rethink our interceptors strategy for that to work