299

I am using Entity Framework and occasionally i will get this error.

EntityCommandExecutionException
{"There is already an open DataReader associated with this Command which must be closed first."}
   at System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands...

Even though i am not doing any manual connection management.

this error happens intermittently.

code that triggers the error (shortened for ease of reading):

        if (critera.FromDate > x) {
            t= _tEntitites.T.Where(predicate).ToList();
        }
        else {
            t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
        }

using Dispose pattern in order to open new connection every time.

using (_tEntitites = new TEntities(GetEntityConnection())) {

    if (critera.FromDate > x) {
        t= _tEntitites.T.Where(predicate).ToList();
    }
    else {
        t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
    }

}

still problematic

why wouldn't EF reuse a connection if it is already open.

Sonic Soul
  • 21,043
  • 31
  • 118
  • 190
  • 1
    I realise that this question is ancient, but I'd be interested to know what type your `predicate` and `historicPredicate` variables are. I've discovered that if you pass `Func` to `Where()` it will compile and sometimes work (because it does the "where" in memory). What you **should** be doing is passing `Expression>` to `Where()`. – James Mar 22 '17 at 13:48

17 Answers17

374

It is not about closing connection. EF manages connection correctly. My understanding of this problem is that there are multiple data retrieval commands executed on single connection (or single command with multiple selects) while next DataReader is executed before first one has completed the reading. The only way to avoid the exception is to allow multiple nested DataReaders = turn on MultipleActiveResultSets. Another scenario when this always happens is when you iterate through result of the query (IQueryable) and you will trigger lazy loading for loaded entity inside the iteration.

Ladislav Mrnka
  • 349,807
  • 56
  • 643
  • 654
  • 2
    that would make sense. but there is only one select within each method. – Sonic Soul Feb 01 '11 at 22:20
  • 1
    @Sonic: That is the question. Maybe there is more then one command executed but you don't see it. I'm not sure if this can be traced in Profiler (exception can be thrown before second reader is executed). You can also try to cast the query to ObjectQuery and call ToTraceString to see the SQL command. It is hard to track. I always turn on MARS. – Ladislav Mrnka Feb 01 '11 at 22:27
  • not sure how tracing would help.. are we looking to see if EF is closing the connection after every call? shouldn't it be recycling it or using a connection pool? in either case, what should i look for in a trace? – Sonic Soul Feb 01 '11 at 22:30
  • 2
    @Sonic: No my intention was to check executed and completed SQL commands. – Ladislav Mrnka Feb 01 '11 at 22:46
  • what were you thinking of looking for in executed sql ? – Sonic Soul Feb 01 '11 at 23:38
  • @Sonic: SQL Profiler is able to show start of command execution and end of command execution. So I guess if you see start of second SELECT before the first one is completed (on the same connection) then it is the source of the problem. Also you can check that each started command contains only single select statement. – Ladislav Mrnka Feb 02 '11 at 08:23
  • if i do use MultipleActiveResultSets, how can i ensure that all connections are properly disposed? – Sonic Soul Feb 02 '11 at 14:43
  • MultipleActiverResultSets don't create any additional connections. It is still one connection with multiple DataReaders. Closing connection (returning it to pool) happens when you dispose ObjectContext. – Ladislav Mrnka Feb 02 '11 at 14:52
  • so there are no possible side effects? why is it disabled by default? – Sonic Soul Feb 02 '11 at 15:20
  • I don't think that there are possible side effects - except rarely possible bugs in framework itself. MARS is turned off by default because it is only supported in SQL Server 2005 and 2008. – Ladislav Mrnka Feb 02 '11 at 15:47
  • 11
    great, my problem was the second scenario: 'when you iterate through result of the query (IQueryable) and you will trigger lazy loading for loaded entity inside the iteration.' – Amr Elgarhy Sep 13 '11 at 23:38
  • The same problem also arises with NHibernate - In my case I removed the lazy loading as I need to support SQL2000 – Tom Carter Apr 16 '13 at 08:51
  • Using EF5, turning MARS on is the equivalent of turning lazy loading off; calls to related entities return null instead of causing the error. – dudeNumber4 Mar 12 '14 at 12:27
  • in our case the problem was, that connection pooling was turned on and MultipleActiveResultSets was not set. after setting MultipleActiveResultSets = true everything worked. – 360Airwalk May 26 '14 at 10:42
  • 7
    Enabling MARS _can_ apparently have bad side-effects: http://www.designlimbo.com/?p=235 – Søren Boisen Jul 10 '15 at 01:35
  • 1
    How about using multiple datacontexts? is it bad practice? – Hossein Shahdoost Apr 21 '16 at 13:57
  • Good question. Is there any major issues with multiple data contexts? – rolls Feb 28 '17 at 12:08
  • 1
    I have resolved this issue just adding **MultipleActiveResultSets=True;** in connection string in web.config. and its working fine; Thanks. – Hardik May 24 '17 at 07:42
  • Is simply creating more contexts (`DbContext` in EF) a valid solution? – Sinjai Aug 21 '17 at 21:35
  • You saved my time. It was about lazy loading. – optim1st Jul 28 '18 at 18:11
  • For me it was IQueryable. I was trying to delete an item in an iteration of Iqueryable. Making the queryable to Tolist() and then deleting sloved it. Hope it helps some one – Rajon Tanducar May 27 '21 at 13:05
136

Alternatively to using MARS (MultipleActiveResultSets) you can write your code so you dont open multiple result sets.

What you can do is to retrieve the data to memory, that way you will not have the reader open. It is often caused by iterating through a resultset while trying to open another result set.

Sample Code:

public class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}

public class Blog
{
    public int BlogID { get; set; }
    public virtual ICollection<Post> Posts { get; set; }
}

public class Post
{
    public int PostID { get; set; }
    public virtual Blog Blog { get; set; }
    public string Text { get; set; }
}

Lets say you are doing a lookup in your database containing these:

var context = new MyContext();

//here we have one resultset
var largeBlogs = context.Blogs.Where(b => b.Posts.Count > 5); 

foreach (var blog in largeBlogs) //we use the result set here
{
     //here we try to get another result set while we are still reading the above set.
    var postsWithImportantText = blog.Posts.Where(p=>p.Text.Contains("Important Text"));
}

We can do a simple solution to this by adding .ToList() like this:

var largeBlogs = context.Blogs.Where(b => b.Posts.Count > 5).ToList();

This forces entityframework to load the list into memory, thus when we iterate though it in the foreach loop it is no longer using the data reader to open the list, it is instead in memory.

I realize that this might not be desired if you want to lazyload some properties for example. This is mostly an example that hopefully explains how/why you might get this problem, so you can make decisions accordingly

Jim Wolff
  • 4,564
  • 4
  • 31
  • 40
  • 8
    This solution worked for me. Add .ToList() right after querying and before doing anything else with the result. – T.J.Kjaer Nov 13 '12 at 14:06
  • 11
    Be careful with this and use common sense. If you're `ToList`ing a thousand objects, it's going to increase memory a ton. In this specific example, you'd be better off combining the inner query with the first so only one query is generated rather than two. – kamranicus Mar 19 '13 at 20:01
  • 4
    @subkamran My point was exactly that, thinking about something and choosing what is right for the situation, not just doing. The example is just something random i thought up to explain :) – Jim Wolff Mar 21 '13 at 08:19
  • 3
    Definitely, I just wanted to point it out explicitly for copy/paste-happy folks :) – kamranicus Mar 22 '13 at 19:55
  • Don't shoot me, but this is in no way a solution to the question. Since when is "pulling data in memory" a solution for a SQL related problem? I like being chatty with the database, so in no way would i prefer to pull something in memory "because otherwise a SQL exception is thrown". Nevertheless, in you're code provided, there's no reason to contact the database twice. Easy to be done in one call. Be careful with posts like this. ToList, First, Single, ... Should only be used when the data is needed in memory (so only the data which u WANT), not when a SQL exception is occuring otherwise. – Frederik Prijck Feb 04 '14 at 09:21
  • As mentioned earlier common sense should be used, but i can think of many scenarios where you might want to cache something in an in-memory dictionary for example. The provided example is just very basic and to explain why this problem is occuring. – Jim Wolff Feb 04 '14 at 09:30
71

There's another way to overcome this problem. Whether it's a better way depends on your situation.

The problem results from lazy loading, so one way to avoid it is not to have lazy loading, through the use of Include:

var results = myContext.Customers
    .Include(x => x.Orders)
    .Include(x => x.Addresses)
    .Include(x => x.PaymentMethods);

If you use the appropriate Includes, you can avoid enabling MARS. But if you miss one, you'll get the error, so enabling MARS is probably the easiest way to fix it.

Ryan Lundy
  • 187,365
  • 35
  • 174
  • 206
  • 1
    Worked like a charm. `.Include` is a much better solution than enabling MARS, and much easier than writing your own SQL query code. – Nolonar Mar 28 '14 at 16:02
  • 16
    If anyone is having the issue that you can only write the .Include("string") not a lambda, you need to add "using System.Data.Entity" because the extension method is located there. – Jim Wolff Aug 07 '14 at 07:26
52

You get this error, when the collection you are trying to iterate is kind of lazy loading (IQueriable).

foreach (var user in _dbContext.Users)
{    
}

Converting the IQueriable collection into other enumerable collection will solve this problem. example

_dbContext.Users.ToList()

Note: .ToList() creates a new set every-time and it can cause the performance issue if you are dealing with large data.

Nalan Madheswaran
  • 8,156
  • 1
  • 48
  • 37
16

Try in your connection string to set MultipleActiveResultSets=true. This allow multitasking on database.

Server=yourserver ;AttachDbFilename=database;User Id=sa;Password=blah ;MultipleActiveResultSets=true;App=EntityFramework

That works for me ... whether your connection in app.config or you set it programmatically ... hope this helpful

Tor
  • 741
  • 1
  • 13
  • 23
Mohamed Hocine
  • 357
  • 4
  • 10
13

I solved the problem easily (pragmatic) by adding the option to the constructor. Thus, i use that only when needed.

public class Something : DbContext
{
    public Something(bool MultipleActiveResultSets = false)
    {
        this.Database
            .Connection
            .ConnectionString = Shared.ConnectionString /* your connection string */
                              + (MultipleActiveResultSets ? ";MultipleActiveResultSets=true;" : "");
    }
...
Harvey Triana
  • 151
  • 1
  • 4
4

I had originally decided to use a static field in my API class to reference an instance of MyDataContext object (Where MyDataContext is an EF5 Context object), but that is what seemed to create the problem. I added code something like the following to every one of my API methods and that fixed the problem.

using(MyDBContext db = new MyDBContext())
{
    //Do some linq queries
}

As other people have stated, the EF Data Context objects are NOT thread safe. So placing them in the static object will eventually cause the "data reader" error under the right conditions.

My original assumption was that creating only one instance of the object would be more efficient, and afford better memory management. From what I have gathered researching this issue, that is not the case. In fact, it seems to be more efficient to treat each call to your API as an isolated, thread safe event. Ensuring that all resources are properly released, as the object goes out of scope.

This makes sense especially if you take your API to the next natural progression which would be to expose it as a WebService or REST API.

Disclosure

  • OS: Windows Server 2012
  • .NET: Installed 4.5, Project using 4.0
  • Data Source: MySQL
  • Application Framework: MVC3
  • Authentication: Forms
3

I noticed that this error happens when I send an IQueriable to the view and use it in a double foreach, where the inner foreach also needs to use the connection. Simple example (ViewBag.parents can be IQueriable or DbSet):

foreach (var parent in ViewBag.parents)
{
    foreach (var child in parent.childs)
    {

    }
}

The simple solution is to use .ToList() on the collection before using it. Also note that MARS does not work with MySQL.

cen
  • 2,673
  • 2
  • 24
  • 51
  • THANK YOU! Everything on here said "nested loops is the problem" but no one said how to fix it. I put a `ToList()` on my first call to get a collection from the DB. Then I did a `foreach` on that list and the subsequent calls worked perfectly instead of giving the error. – AlbatrossCafe Jan 21 '17 at 00:42
  • @AlbatrossCafe ...but no one mentions that in that case your data will be loaded to memory and query will be executed in memory, instead of DB – Lightning3 Aug 30 '17 at 08:06
3

I found that I had the same error, and it occurred when I was using a Func<TEntity, bool> instead of a Expression<Func<TEntity, bool>> for your predicate.

Once I changed out all Func's to Expression's the exception stopped being thrown.

I believe that EntityFramwork does some clever things with Expression's which it simply does not do with Func's

sQuir3l
  • 1,315
  • 7
  • 10
  • This needs more upvotes. I was trying to craft a method in my DataContext class taking in a `(MyTParent model, Func func)` so that my ViewModels could specify a certain `where` clause to the Generic DataContext method. Nothing was working until I did this. – Justin Mar 12 '19 at 20:31
3

2 solutions to mitigate this problem:

  1. Force memory caching keeping lazy loading with .ToList() after your query, so you can then iterate through it opening a new DataReader.
  2. .Include(/additional entities you want to load in the query/) this is called eager loading, which allows you to (indeed) include associated objects(entities) during he execution of a query with the DataReader.
gameon67
  • 3,119
  • 2
  • 24
  • 44
2

A good middle-ground between enabling MARS and retrieving the entire result set into memory is to retrieve only IDs in an initial query, and then loop through the IDs materializing each entity as you go.

For example (using the "Blog and Posts" sample entities as in this answer):

using (var context = new BlogContext())
{
    // Get the IDs of all the items to loop through. This is
    // materialized so that the data reader is closed by the
    // time we're looping through the list.
    var blogIds = context.Blogs.Select(blog => blog.Id).ToList();

    // This query represents all our items in their full glory,
    // but, items are only materialized one at a time as we
    // loop through them.
    var blogs =
        blogIds.Select(id => context.Blogs.First(blog => blog.Id == id));

    foreach (var blog in blogs)
    {
        this.DoSomethingWith(blog.Posts);

        context.SaveChanges();
    }
}

Doing this means that you only pull a few thousand integers into memory, as opposed to thousands of entire object graphs, which should minimize memory usage while enabling you to work item-by-item without enabling MARS.

Another nice benefit of this, as seen in the sample, is that you can save changes as you loop through each item, instead of having to wait until the end of the loop (or some other such workaround), as would be needed even with MARS enabled (see here and here).

Community
  • 1
  • 1
Paul
  • 376
  • 4
  • 14
1

In my case I found that there were missing "await" statements before myContext.SaveChangesAsync() calls. Adding await before those async calls fixed the data reader issues for me.

Elijah Lofgren
  • 1,367
  • 2
  • 22
  • 38
0

If we try to group part of our conditions into a Func<> or extension method we will get this error, suppose we have a code like this:

public static Func<PriceList, bool> IsCurrent()
{
  return p => (p.ValidFrom == null || p.ValidFrom <= DateTime.Now) &&
              (p.ValidTo == null || p.ValidTo >= DateTime.Now);
}

Or

public static IEnumerable<PriceList> IsCurrent(this IEnumerable<PriceList> prices) { .... }

This will throw the exception if we try to use it in a Where(), what we should do instead is to build a Predicate like this:

public static Expression<Func<PriceList, bool>> IsCurrent()
{
    return p => (p.ValidFrom == null || p.ValidFrom <= DateTime.Now) &&
                (p.ValidTo == null || p.ValidTo >= DateTime.Now);
}

Further more can be read at : http://www.albahari.com/nutshell/predicatebuilder.aspx

Arvand
  • 3,793
  • 3
  • 27
  • 36
0

This problem can be solved simply by converting the data to a list

 var details = _webcontext.products.ToList();


            if (details != null)
            {
                Parallel.ForEach(details, x =>
                {
                    Products obj = new Products();
                    obj.slno = x.slno;
                    obj.ProductName = x.ProductName;
                    obj.Price = Convert.ToInt32(x.Price);
                    li.Add(obj);

                });
                return li;
            }
Debendra Dash
  • 3,944
  • 35
  • 32
  • the ToList() makes the call but above code still does not dispose the connection. so your _webcontext is still at risk for being closed at the time of line 1 – Sonic Soul Jun 16 '17 at 20:19
0

In my situation the problem occurred because of a dependency injection registration. I was injecting a per request scope service that was using a dbcontext into a singleton registered service. Therefor the dbcontext was used within multiple request and hence the error.

E. Staal
  • 375
  • 3
  • 15
0

In my case the issue had nothing to do with MARS connection string but with json serialization. After upgrading my project from NetCore2 to 3 i got this error.

More information can be found here

OrElse
  • 8,657
  • 36
  • 127
  • 234
-6

I solved this problem using the following section of code before the second query:

 ...first query
 while (_dbContext.Connection.State != System.Data.ConnectionState.Closed)
 {
     System.Threading.Thread.Sleep(500);
 }
 ...second query

you can change the time of sleep in miliseconds

P.D. Useful when using threads

i31nGo
  • 1
  • 13
    Arbitrarily adding Thread.Sleep in any solution is bad practice - and is especially bad when used to sidestep a different problem where the state of some value is not entirely understood. I would have thought that "Using Threads" as stated at the bottom of the response would mean having at least some basic understanding of threading - but this response doesn't take any context into account, especially those circumstances where it is a very bad idea to use Thread.Sleep - such as on a UI thread. – Mike Tours Aug 19 '13 at 09:32