Pourquoi est-il possible d'énumérer une requête DbLinq après avoir appelé Dispose () sur le DataContext?

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

  •  27-09-2019
  •  | 
  •  

Question

Mise à jour - La réponse est apparemment que DbLinq ne met pas en œuvre correctement Dispose(). D'oh!


Le dessous est toutes sortes d'induire en erreur - Bottom line: DbLinq est pas (encore) équivalent à LinqToSql, comme je supposais quand j'ai demandé à l'origine de cette question. Utilisez-le avec précaution!

J'utilise le modèle du référentiel avec DbLinq. Mes objets du référentiel IDisposable mettre en œuvre, et la méthode ne Dispose() seule chose - les appels Dispose() sur le DataContext. Chaque fois que j'utiliser un référentiel, je l'enveloppe dans un bloc de using, comme ceci:

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

Cette méthode retourne un IEnumerable<Person>, donc si je comprends bien, pas l'interrogation de la base de données a effectivement lieu jusqu'à ce que Enumerable<Person> est traversée (par exemple, en le convertissant en une liste ou un tableau ou en utilisant dans une boucle de foreach), comme dans cet exemple:

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

Dans cet exemple, Dispose() est appelé immédiatement après la mise en persons, qui est un IEnumerable<Person>, et qui est le seul moment où il est appelé.

Alors, trois questions:

  1. Comment ça marche? Comment un DataContext toujours disposé interroger la base de données des résultats après la DataContext a été disposé?
  2. Qu'est-ce que Dispose() fait faire?
  3. Je l'ai entendu dire que ce n'est pas nécessaire (par exemple, voir cette question ) de disposer d'un DataContext, mais mon impression est que ce n'est pas une mauvaise idée. Y at-il raison pas de disposer d'un DataContext DbLinq?
Était-ce utile?

La solution

  

1 Comment ça marche? Comment un DataContext toujours disposé interroger la base de données des résultats après la DataContext a été disposé?

ne pas travail. Il y a quelque chose que vous n'êtes pas nous montrer. Je devine que soit votre classe référentiel ne pas disposer les DataContext correctement / au bon moment, ou que vous écrivez perfunctorily ToList() à la fin de chaque requête, ce qui annule complètement la transformation de la requête et l'exécution différée, vous obtenez normalement.

Essayez le code suivant dans une application de test, I garantie vous qu'il va jeter 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);
}

Ceci est le cas le plus simple reproductible possible, et il sera toujours jeter. D'autre part, si vous écrivez people = context.Person.ToList() à la place, les résultats de la requête ont déjà été énumérées dans le bloc using, que je vais est mise ce qui se passe dans votre cas.

  

2 Qu'est-ce que Dispose () réellement faire?

Entre autres, il établit un drapeau indiquant que le DataContext est disposé, qui est vérifié sur toutes les requêtes ultérieures et provoque la DataContext de jeter un ObjectDisposedException avec le message Object name: 'DataContext accessed after Dispose.'.

Il ferme également la connexion, si l'DataContext ouvrit et a laissé ouvert.

  

3 Je l'ai entendu dire qu'il est pas nécessaire (par exemple, voir cette question) de disposer d'un DataContext, mais mon impression est que ce n'est pas une mauvaise idée. Y at-il raison de ne pas disposer d'un DataContext LinqToSql?

est nécessaire pour Dispose le DataContext, comme il est nécessaire de Dispose tous les IDisposable. Vous pourriez potentiellement fuir les connexions si vous ne parvenez pas à éliminer la DataContext. Vous pouvez également fuite de mémoire si l'une des entités extraites de la DataContext sont maintenus en vie, puisque le contexte maintient un cache d'identité interne pour l'unité de travail modèle il met en œuvre. Mais même si rien de tout cela était le cas, il ne vous concerne pas ce que la méthode Dispose fait en interne. On suppose qu'il fait quelque chose d'important.

IDisposable est contrat qui dit: « le nettoyage ne peut pas être automatique, vous devez me jeter lorsque vous avez terminé. » Vous avez aucune garantie de savoir si l'objet a sa propre finaliseur qui nettoie ou non après vous si vous oubliez de Dispose. Les implémentations sont sujets à changement, ce qui est pourquoi il est pas une bonne idée de se fonder sur le comportement observé par opposition aux spécifications explicites.

La pire chose qui peut se produire si vous disposez d'un IDisposable avec une méthode Dispose vide est que vous perdez quelques cycles CPU. La pire chose qui peut arriver si vous ne pas de disposer d'un IDisposable avec mise en œuvre non trivial il est que vous fuyez les ressources. Le choix est évident ici; si vous voyez un IDisposable, ne pas oublier de le disposer.

Autres conseils

"personnes" est une collection IEnumerable, le DataContext (dépôt) est uniquement nécessaire pour effectuer l'appel .GetNew.

de / select / etc mots-clés sont le sucre syntaxique pour les méthodes d'extension ajoutés dans l'espace de noms System.Linq. Ces méthodes d'extension ajouter la fonctionnalité IEnumerable que vous utilisez dans votre requête, et non pas le DataContext. En fait, vous pouvez faire tout cela sans utiliser LINQ2SQL du tout, en créant un IEnumerable programatically démontrer.

Si vous essayez de faire un dépôt plus (DataContext) appelle l'utilisation de ces objets, qui est quand vous recevez une erreur.

La collection IEnumerable contiendra tous les enregistrements de votre dépôt, c'est pourquoi vous ne souhaitez pas le DataContext pour faire la requête.

Méthodes d'extension: http://msdn.microsoft.com/en- nous / bibliothèque / bb383977.aspx

Méthodes d'extension LINQ: http://msdn.microsoft.com/en-us/ bibliothèque / system.linq.enumerable_members.aspx

Au plus profond de l'API, vous verrez probablement un procédé utilisant un api comme celui-ci:

http://msdn.microsoft. com / fr-fr / bibliothèque / y6wy5a0f (v = VS.100) .aspx

Lorsque la commande est exécutée, l'objet de connexion associé est fermé lorsque l'objet DataReader associé est fermé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top