10

I am working on a project to connect to PostgreSQL database using NpGsql EntityFramework 6. I am getting the exception in question heading, when I try to execute the query in GetAdminUsersCount:

public class GenieRepository : IDisposable
{
    GenieDbContext db = new GenieDbContext();
    public IEnumerable<User> GetUsers()
    {
        return db.Users;
    }   
}

public int GetAdminUsersCount()
{
    return repo.GetUsers().Where(u => u.Role.RoleName == "Administrator").Count();
}

What is the reason for this error and how to resolve it?

Vivek S.
  • 19,945
  • 7
  • 68
  • 85
teenup
  • 7,459
  • 13
  • 63
  • 122

2 Answers2

8

Use a ToList<T> right after the LINQ query like this:

using (ElisContext db = new ElisContext()) {
    var q = from a in db.aktie select a;
    List<aktie> akties = q.ToList<aktie>();
    foreach (aktie a in akties) {
        Console.WriteLine("aktie: id {0}, name {1}, market name {2}"
                 , a.id, a.name, a.marked.name);
    }
}

Note the q.ToList<T> which does the trick. .NET delays the execution of the linq statement to the latest moment, which may be part of the problem. I have tried to use q in the foreach without success.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Jan Rou
  • 151
  • 2
  • 10
4

The issue is caused by the return type of the GetUsers() method. Since it is IEnumerable<User>, LINQ-to-SQL will load the result into memory (row by row) and subsequent Where, OrderBy, Select, Count, etc. calls will be executed in memory. When the Where condition is evaluated, the original result set is still being iterated over, but the relation User.Role needs to be resolved on the DB (that's where the "An operation is already in progess" error message comes from).

If the return type is changed to IQueryable<User>, the query won't be executed until the Count method is called, and furthermore, the whole query will be translated into SQL returning only the count without ever loading any User records into memory.

See also this related question/answer: Returning IEnumerable<T> vs. IQueryable<T>

The answer suggesting to call ToList() on the query, will load the entire result set into memory, which makes your error go away, but depending on the size of the result set, could also be very inefficient.

forrert
  • 4,109
  • 1
  • 26
  • 38