Attacher et détacher correctement les entités du contexte dans EF4.(1)

j'essaie d'implémenter un mécanisme de mise en cache pour les entities. Et pour utiliser les entities correctement et de manière transparente avec la mise en cache, je dois détacher l'entity du contexte actuel avant de le mettre dans un cache et de le rattacher au nouveau contexte lorsque je l'obtiens du cache. (Mon contexte de vie est par requête http)

les exigences sont que -

  1. toutes les propriétés de navigation qui lui sont associées (que j'ai déjà rempli) ne doit pas être supprimé lorsque l'entité est détachée.
  2. je peux mettre à jour les éléments mis en cache si je veux ( il est donc important de les attacher correctement au nouveau contexte).

c'est ma tentative de créer une classe EntityCache - (ServerCache voici ma classe wrapper qui pousse l'objet à ASP.NET cache)

public static class EntityCache
    {
        private static DbContext context
        {
            get
            {
                return (DbContext)HttpContext.Current.Items[ObjectKeys.ContextRequestItemKey];
            }
        }

        private static void Detach(object entity)
        {
            var trackedEntity = entity as IEntityWithChangeTracker;
            trackedEntity.SetChangeTracker(null);
            ((IObjectContextAdapter)context).ObjectContext.Detach(entity);
        }

        private static void Attach(object entity)
        {
            ((IObjectContextAdapter)context).ObjectContext.Attach((IEntityWithKey)entity);
        }

        public static void Remove(string key)
        {
            ServerCache.Remove(key);
        }

        public static object Get(string key)
        {
            object output = ServerCache.Get(key);
            if (output != null)
                Attach(output);
            return output;
        }

        public static void ShortCache(String key, object data)
        {
            if (data != null)
            {
                Detach(data);
                ServerCache.ShortCache(key, data);
            }
        }

        public static void LongCache(String key, object data)
        {
            if (data != null)
            {
                Detach(data);
                ServerCache.LongCache(key, data);
            }
        }
    }

quand je mets une entité dans le cache, elle est de type DynamicProxy et non pas la vraie classe.

attacher ne fonctionne pas du tout - j'obtiens une exception que je ne peux pas Cas objet qui est de type Dynamic_{blahblah} à IEntityWithKey.

je viens de voir ces exemples de attacher et détacher en ligne et les ai essayés, je suis ouvert à toute nouvelle mise en œuvre des méthodes D'attache/détacher ici.

Merci.

question de suivi -

context.Entry(entity).State = EntityState.Detached;

fonctionne, mais rend tous les propriétés qui sont chargées NULL, comment le faire garder les propriétés de navigation et ne pas les remplacer (ou les perdre) par NULL lorsque nous nous détachons du contexte.

31
demandé sur MoXplod 2011-10-06 22:15:39

2 réponses

IEntityWithKey est une interface pour d'autres types d'entités. C'est pour les "gros" des entités. Par exemple EntityObject implémenter cette interface. Ces entités ne sont pas considérées comme POCO et ne sont pas supportées par L'API DbContext .

si vous voulez utiliser IEntityWithKey vos classes doivent l'implémenter - ce n'est pas quelque chose qui se produirait automatiquement.

fixation correcte avec DbContext API devrait être:

dbContext.Set(typeof(entity)).Attach(entity); 

et cela devrait aussi fonctionner:

dbContext.Entry(entity).State = EntityState.Unchanged;

Corriger les détacher avec DbContext API devrait être:

dbContext.Entry(entity).State = EntityState.Detached;

aussi il vaut mieux pour vous des méthodes génériques au lieu de object .

29
répondu Ladislav Mrnka 2013-05-22 12:11:04

à votre question de suivi:

...comment faire pour qu'il conserve les propriétés de navigation et non les remplacer (ou les perdre) par NULL lorsque nous nous détachons du contexte...

je crois qu'il n'est pas possible de détacher un graphique objet du contexte tout en maintenant ses propriétés de navigation. à Partir de MSDN :

dans une association indépendante, la les informations de relation n'est pas maintenu pour un objet détaché.

bien que cette déclaration concerne les associations indépendantes, cela ne signifie pas que les propriétés de navigation sont maintenues dans l'association de clés étrangères (relations qui exposent une propriété de clé étrangère dans le modèle). Oui, "information sur la relation" est conservée parce que les propriétés de la clé étrangère (qui sont des propriétés scalaires) seront vivantes et contiendront la valeur correcte de la clé étrangère après détacher. Mais les propriétés de navigation correspondantes seront toujours null pour les propriétés de référence ou, pour les collections de navigation, la référence sera retirée de la collection.

je pense que la seule façon de détacher un graphe objet complet d'un contexte est soit d'éliminer complètement le contexte ou de créer une copie du graphe avant de commencer à détacher le graphe original. La création d'une copie nécessiterait l'écriture des méthodes Clone qui copient toutes les propriétés et naviguer à travers le graphe ou en utilisant un "truc" comme ce qui sérialise le graphe dans un flux binaire et le deserialise ensuite à nouveau à de nouveaux objets. Pour cela, les entités doivent être sérialisables. De plus, les cycles de référence (que nous avons souvent lorsque nous utilisons des propriétés de navigation bidirectionnelles entre entités) peuvent causer des problèmes. (Attention également si vos objets sont des mandataires qui contiennent des références aux objets internes de EF et que vous ne voulez probablement pas copier, sérialiser et désérialiser.)

Attach à cet égard, Detach n'est pas la contrepartie de Attach parce qu'elle se comporte tout à fait différemment: Attach fixe le graphe objet entier et maintient les propriétés de navigation. Detach ne détache que des entités isolées sans les objets correspondants et détruit les propriétés de navigation. De la même page liée ci-dessus:

Détacher affecte uniquement l'objet spécifique passés à la méthode. Si le objet détaché des objets dans le contexte de l'objet, ces les objets ne sont pas détachés.

j'imagine que c'est la raison principale pour laquelle L'API DbContext n'a pas de méthode explicite Detach (par opposition à ObjectContext ) - la désactivation est considérée comme une fonctionnalité avancée qui ne se comporte pas comme on pourrait s'y attendre.

MSDN mentionne comme seule raison pour détacher un objet du contexte "pour préserver les ressources" (encore une fois l'article ci-dessus):

dans les applications Entity Framework, vous pouvez détacher des objets contexte de l'objet. Vous pourriez détacher des objets pour conserver des ressources, comme l'exécution de requêtes répétées dans le même contexte objet Augmente la les exigences de mémoire du contexte de l'objet.

je pense que cette méthode est tout simplement pas préparé et conçu pour travailler avec les objets après avoir été détaché du contexte. Son but principal est de les libérer pour une collecte immédiate des ordures.

10
répondu Slauma 2017-05-23 11:54:22