Perché è possibile enumerare una query DbLinq dopo aver chiamato Dispose () sul DataContext?

StackOverflow https://stackoverflow.com/questions/2851755

  •  27-09-2019
  •  | 
  •  

Domanda

Aggiorna - La risposta è apparentemente che DbLinq non implementa Dispose() correttamente. D'oh!


Il sotto è tutto sorta di fuorviante - Bottom line: DbLinq non è (ancora) equivalente a LinqToSql, come ho assunto quando ho inizialmente fatto questa domanda. Usare con cautela!

Sto utilizzando il Pattern Repository con DbLinq. I miei oggetti di repository implementare IDisposable, e il metodo Dispose() fa unica cosa - le chiamate Dispose() sul DataContext. Ogni volta che uso un repository, mi avvolgo in un blocco using, in questo modo:

public IEnumerable<Person> SelectPersons()
{
    using (var repository = _repositorySource.GetPersonRepository())
    {
        return repository.GetAll(); // returns DataContext.Person as an IQueryable<Person>
    }
}

Questo metodo restituisce un IEnumerable<Person>, quindi se la mia comprensione è corretta, non l'interrogazione del database avviene effettivamente fino a quando è attraversato Enumerable<Person> (ad esempio, convertendolo in un elenco o una matrice o utilizzando in un ciclo foreach), come in questo esempio:

var persons = gateway.SelectPersons();
// Dispose() is fired here
var personViewModels = (
    from b in persons
    select new PersonViewModel
    {
        Id = b.Id,
        Name = b.Name,
        Age = b.Age,
        OrdersCount = b.Order.Count()
    }).ToList(); // executes queries

In questo esempio, Dispose() viene chiamato immediatamente dopo l'impostazione persons, che è un IEnumerable<Person>, e questa è l'unica volta che viene chiamato.

Quindi, tre domande:

  1. Come funziona? Come può un DataContext disposto ancora interrogare il database per i risultati dopo la DataContext è stato eliminato?
  2. Cosa fa Dispose() effettivamente fare?
  3. Ho sentito che non è necessario (ad esempio, vedere questa domanda ) di disporre di un DataContext, ma la mia impressione è che non è una cattiva idea. C'è qualche ragione non di disporre di un DataContext DbLinq?
È stato utile?

Soluzione

  

1 Come funziona? Come può un DataContext disposto ancora interrogare il database per i risultati dopo il DataContext è stato eliminato?

non il lavoro. C'è qualcosa che non sta mostrando noi. Sto indovinando che sia la classe repository non smaltire il DataContext correttamente / al momento giusto, o che si sta scrivendo sommariamente ToList() alla fine di ogni query, che nega completamente la trasformazione query e l'esecuzione differita si ottiene generalmente.

Prova il seguente codice in un'applicazione di test, I garanzia che si genera un ObjectDisposedException:

// Bad code; do not use, will throw exception.
IEnumerable<Person> people;
using (var context = new TestDataContext())
{
    people = context.Person;
}
foreach (Person p in people)
{
    Console.WriteLine(p.ID);
}

Questo è il più semplice caso riproducibili possibile, e sarà sempre buttare. D'altra parte, se si scrive people = context.Person.ToList() invece, allora i risultati della query sono già state enumerate all'interno il blocco using, che scommetto è quello che sta succedendo nel vostro caso.

  

2 Cosa significa Dispose () in realtà fare?

Tra le altre cose, si imposta un flag che indica che il DataContext è disposto, che viene controllata in ogni query successiva e fa sì che il DataContext di gettare un ObjectDisposedException con il messaggio Object name: 'DataContext accessed after Dispose.'.

Si chiude anche il collegamento, se il DataContext apri e lasciata aperta.

  

3 Ho sentito dire che non è necessario (ad esempio, vedere questa domanda) di disporre di un DataContext, ma la mia impressione è che non è una cattiva idea. C'è qualche motivo per non disporre di un LinqToSql DataContext?

è necessario Dispose la DataContext, in quanto è necessario per Dispose ogni altro IDisposable. Si potrebbe potenzialmente perdere connessioni se non si riesce a smaltire il DataContext. Si potrebbe anche perdere la memoria se una qualsiasi delle entità recuperati dal DataContext sono tenuti in vita, poiché il contesto mantiene una cache identità interna per il modello di unità di lavoro da essa svolte. Ma anche se tutto questo non fosse il caso, non è la vostra preoccupazione ciò che il metodo Dispose fa internamente. Si supponga che si fa qualcosa di importante.

IDisposable è un contratto che dice: "la pulizia non può essere automatico, è necessario disporre di me quando hai finito." Non ci sono garanzie di se l'oggetto ha un proprio finalizzatore che pulisce dopo di voi, se si dimentica di Dispose. Implementazioni sono soggette a cambiamenti, ed è per questo che non è una buona idea fare affidamento su comportamento osservato in contrasto con le specifiche esplicite.

La cosa peggiore che può accadere se si smaltisce un IDisposable con un metodo Dispose vuoto è che si rifiuti di un paio di cicli di CPU. La cosa peggiore che può accadere se si fallire per smaltire un IDisposable con un implementazione non banali è che si perdita di risorse. La scelta qui è evidente; se vedete un IDisposable, non dimenticate di smaltire.

Altri suggerimenti

"persone" è una raccolta IEnumerable, il DataContext (repository) è necessaria solo per effettuare la chiamata .GetNew.

lo zucchero da / select / etc parole chiave sono sintattica per i metodi di estensione aggiunti nello spazio dei nomi System.Linq. Questi metodi di estensione aggiungere la funzionalità IEnumerable si utilizza nella query, non il DataContext. In realtà, si può fare tutto questo senza usare LINQ2SQL a tutti, per la creazione di un programatically IEnumerable per dimostrare.

Se si tenta di fare ulteriori repository (DataContext) chiamate utilizzando questi oggetti, che è quando si riceve un errore.

La raccolta IEnumerable conterrà tutti i record dalla repository, questo è il motivo per cui non si richiede il DataContext per rendere la query.

metodi di estensione: http://msdn.microsoft.com/en- us / library / bb383977.aspx

metodi di estensione LINQ: http://msdn.microsoft.com/en-us/ biblioteca / system.linq.enumerable_members.aspx

Nel profondo l'API, probabilmente vedrete un metodo che utilizza un API come questo:

http://msdn.microsoft. com / it-it / library / y6wy5a0f (v = VS.100) aspx

Quando viene eseguito il comando, l'oggetto di connessione viene chiuso quando l'oggetto DataReader associato chiuso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top