2015-12-31 19 views
9

Sto lavorando a un progetto per connettersi al database PostgreSQL utilizzando NpGsql EntityFramework 6. Ricevo l'eccezione nell'intestazione della domanda, quando provo a eseguire la query in GetAdminUsersCount:NpGsql EntityFramework 6 - "Un'operazione è già in corso"

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(); 
} 

Qual è il motivo di questo errore e come risolverlo?

+1

SideNote: ** PostGre Sql **: O, eh ??? Usa [Postgres o PostgreSQL] (http://stackoverflow.com/tags/postgresql/info) –

+0

Quale versione di NpgSql usi? Se si distribuisce su mono quale versione è? –

+0

NpgSql 3.0.4.0, Entity Framework 6.0 – teenup

risposta

7

sono riuscito a risolvere il problema utilizzando un ToList<T> subito dopo la query LINQ in questo modo:

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); 
    } 
} 

Nota la q.ToList<T> che fa il trucco. .Net rimandare l'esecuzione dell'istruzione linq all'ultimo momento, che potrebbe essere parte del problema. Ho provato ad usare q in foreach senza successo.

2

Il problema è causato dal tipo di ritorno del metodo GetUsers(). Poiché è IEnumerable<User>, LINQ-to-SQL caricherà il risultato in memoria (riga per riga) e successivo Where, OrderBy, Select, Count, ecc. Le chiamate verranno eseguite in memoria. Quando viene valutata la condizione Where, il set di risultati originale viene ancora iterato, ma la relazione User.Role deve essere risolta sul DB (è qui che viene visualizzato il messaggio di errore "Un'operazione è già in corso").

Se il tipo di ritorno viene modificato IQueryable<User>, la query non verrà eseguita finché il metodo Count viene chiamato, e inoltre, l'intera query sarà tradotto in SQL restituendo solo il conteggio senza mai caricare qualsiasi User record in memoria .

Vedi anche questa relativa domanda/risposta: Returning IEnumerable<T> vs. IQueryable<T>

La risposta che suggerisce di chiamare ToList() sulla query, verrà caricato l'intero set di risultati in memoria, il che rende il vostro errore andare via, ma a seconda delle dimensioni del set di risultati, potrebbe anche essere molto inefficiente.