2010-04-04 3 views
7

Je viens de découvrir que le chargement paresseux dans Entity Framework fonctionne uniquement à partir du thread qui a créé le ObjectContext. Pour illustrer le problème, j'ai fait un test simple, avec un modèle simple contenant seulement 2 entités: Person et Address. Voici le code:Entity Framework chargement paresseux ne fonctionne pas à partir d'un autre thread

private static void TestSingleThread() 
    { 
     using (var context = new TestDBContext()) 
     { 
      foreach (var p in context.Person) 
      { 
       Console.WriteLine("{0} lives in {1}.", p.Name, p.Address.City); 
      } 
     } 
    } 

    private static void TestMultiThread() 
    { 
     using (var context = new TestDBContext()) 
     { 
      foreach (var p in context.Person) 
      { 
       Person p2 = p; // to avoid capturing the loop variable 
       ThreadPool.QueueUserWorkItem(
        arg => 
        { 
         Console.WriteLine("{0} lives in {1}.", p2.Name, p2.Address.City); 
        }); 
      } 
     } 
    } 

La méthode TestSingleThread fonctionne très bien, la propriété Address est chargé paresseusement. Mais dans TestMultiThread, j'obtiens un NullReferenceException sur p2.Address.City, parce que p2.Address est nul.

C'est un bug? Est-ce la façon dont il est censé fonctionner? Si oui, y a-t-il des documents qui le mentionnent? Je ne pouvais pas trouver quelque chose sur le sujet sur MSDN ou Google ...

Et plus important encore, existe-t-il une solution de contournement? (Autre que d'appeler explicitement LoadProperty du thread de travail ...)

Toute aide serait très apprécié

PS: J'utilise VS2010, il est donc EF 4.0. Je ne sais pas si c'était la même chose dans la version précédente de EF ...

+1

Je ne suis pas sûr de votre motivation, mais l'équipe .NET semble encourager le code à être écrit avec Tâche et Action au lieu de faire une utilisation explicite du pool de threads. Peut-être que quelqu'un peut fournir une bonne citation de cela? –

+0

Pouvez-vous élaborer un peu sur l'utilisation de 'p2'? Je suppose que ça n'a rien changé? –

+0

@jarrett: peut-être, mais ce n'est pas le point ... le problème aurait été le même avec une tâche, puisqu'elle utilise des threads quand même. @Henk: ça ne marche pas non plus sans 'p2', mais de toute façon c'est nécessaire, sinon chaque lambda se referme sur la même variable; voir cet article pour plus de détails: http://blogs.msdn.com/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx –

Répondre

7

Est-ce intentionnel? Oui; tout appel à charger, implicite ou explicite, finira par passer par les ObjectContext et ObjectContext is documented to be not thread-safe.

Une solution de contournement possible consiste à détacher l'entité du contexte d'objet dans le thread de travail et à l'attacher à un contexte d'objet dans le thread en cours.

+0

Merci pour votre réponse. Malheureusement, dans mon cas, créer un autre contexte d'objet est définitivement exagéré. J'essaie de charger des images dans une application WPF en utilisant une liaison asynchrone, et je ne veux vraiment pas créer un nouveau contexte pour chaque image (environ 150 images actuellement) –

+0

Je pense que vous avez une question WPF à ce stade , pas une question EF. Les règles de l'EF sont très simples. Comment les suivre en utilisant WPF est un autre problème. –

+0

Eh bien, je l'utilise dans WPF, mais ce n'est pas un problème spécifique à WPF. Et la seule chose à propos de l'enfilage dans la documentation est l'information habituelle sur la sécurité des threads qui est la même pour presque toutes les classes. Il est dit que * ne sont pas garantis être thread safe *, pas * ne peut pas être utilisé par plusieurs threads *. Ne pas être thread-safe ne signifie pas que vous ne pouvez pas utiliser du multi-thread, cela signifie simplement que vous devez gérer la synchronisation vous-même. –

Questions connexes