Search code examples
c#linqparallel.foreach

Getting "Open DataReader" error from in-memory List in Parallel.Foreach


My apologies if this has been asked but I'm running Parallel.Foreach to speed up business logic and passing in 4 partitions of List<item>.

A particular query on an in-memory list is throwing a "The connection was not closed. The connection's current state is connecting." error and when continuing through a "There is already an open DataReader associated with this Command which must be closed first" error. The list is in-memory from an earlier database call before the Parallel.Foreach code and that database call is ended with a ToList() (closing the connection I believe).

I thought errors like this were from making database calls in parallel, so I'm wondering what I'm missing here. Here's the LINQ query throwing the error:

List<item> itemList= Items.Where(m => m.Property1?.Property2 == specificValue).ToList();

Parallel.ForEach setup/code

//There are four 'chunks' of about 500 items each
Parallel.ForEach(chunks, new ParallelOptions() { MaxDegreeOfParallelism = 4 }, chunk =>{
foreach (Case cas in chunk)
{
    List<item> itemList= Items.Where(m => m.Property1?.Property2 == 
    cas.Id).ToList();
    ...other business logic
}

}

Solution

  • Your error is indeed because you are making database calls in parallel. I assume you are using Entity Framework (EF) and have the default as "Lazy Loading" from the DB. Even after the .ToList() if any related items were not being used it hasn't loaded them from the DB yet.

    The Parallel.ForEach() will execute your Items.Where().ToList() for all "4 chunks" concurrently. Since the .Where() requires item properties for comparison it will finally load from the DB. So its attempting to make 4 DB connections concurrently and with EF you can't have concurrent DB calls.

    You should try "Eager Loading" the Items before the Parallel.ForEach.

    https://www.c-sharpcorner.com/article/eager-loading-lazy-loading-and-explicit-loading-in-entity-framework/