0

I'm migrating from netcoreapp 2.1 to 3.1, and I've found a breaking change for EF core 3.1 that I can't resolve.

Previously in 2.1, this worked:

taskList.Add(MethodOne(myRequestObject));
taskList.Add(MethodTwo(myRequestObject));

await Task.WhenAll(taskList);

where both methods only read(never changed) from the db context and look something like this:

private async Task MethodOne(RequestObject myRequestObject)
{
    var entity = await DbContext
    .MyDbSet
    .OrderByDescending(x => x.SomeProperty)
    .FirstOrDefaultAsync(x => x.Id == myRequestObject.Id);

    if (entity != null)
        myRequestObject.SomeRequestProperty = entity.AnotherProperty;
    }
}

In 3.1, even when I'm just reading and not changing the entities, the DB context ConcurrencyDetector thinks it has EnterCriticalSection which causes an exception when the second method tries to await on the DbContext:

InvalidOperationException: A second operation started on this context before a previous operation completed

So, to work around this I replaced await Task.WhenAll(taskList) with the following:

foreach (var task in taskList)
{
    await task;
}

However, this does not work. The same error occurs, as if the second method begins execution without waiting for the first.

For baseline sanity, I also tried the following which does work(but is not an ideal solution for the real code of my app):

await MethodOne(myRequestObject);
await MethodTwo(myRequestObject);

So here are my questions:

  1. Is there a way to continue to tell EF core 3.1 to allow concurrency when I know it is safe.

  2. If not, why the heck is my foreach workaround not working?

  • 1
    1. No. 2. Because calling the method *starts* the task. The `await` waits for it to complete. The DbContext and DbSets are *not* thread safe. This is by design, not a bug. It has been this way ever since inception. – Igor Mar 06 '20 at 18:15
  • Ya, I am apparently too tired to realize that I was evaluating the methods, thus starting them. I fixed that by using a list of Funcs. – Brad Sherard Mar 06 '20 at 18:33
  • I just want to clarify that the error isn't exactly due to `DbContext` not being thread safe, as awaiting a task doesn't rely on multi-threading. The problem is multiple concurrently open reads, which can happen on a single thread as in above code. – Bradley Uffner Mar 06 '20 at 18:48
  • It's "by design" - see the **Warning** in the EF Core docs for [Asynchronous Queries](https://learn.microsoft.com/en-us/ef/core/querying/async). The fact that it "worked" before is irrelevant. Even though your code is just reading, there are still many other shared things like change tracker, connection open/close etc. which are not thread-safe. – Ivan Stoev Mar 06 '20 at 19:50

0 Answers0