Entity Framework 4, objets POCO et ASP.Net MVC2. J'ai une relation plusieurs à plusieurs, disons entre les entités BlogPost et Tag. Cela signifie que dans ma classe POCO BlogPost générée par T4, j'ai:
public virtual ICollection<Tag> Tags {
// getter and setter with the magic FixupCollection
}
private ICollection<Tag> _tags;
Je demande un BlogPost et les balises associées à partir d'une instance de l'ObjectContext et je l'envoie à une autre couche (vue dans l'application MVC). Plus tard, je récupère le BlogPost mis à jour avec des propriétés modifiées et des relations modifiées. Par exemple, il avait des balises "A", "B" et "C", et les nouvelles balises sont "C" et "D". Dans mon exemple particulier, il n'y a pas de nouvelles balises et les propriétés des balises ne changent jamais, donc la seule chose qui devrait être enregistrée est les relations modifiées. Maintenant, je dois enregistrer cela dans un autre ObjectContext. (Mise à jour: maintenant, j'ai essayé de le faire dans la même instance de contexte et j'ai également échoué.)
Le problème: je ne peux pas le faire enregistrer correctement les relations. J'ai essayé tout ce que j'ai trouvé:
- Controller.UpdateModel et Controller.TryUpdateModel ne fonctionnent pas.
- Récupérer l'ancien BlogPost du contexte puis modifier la collection ne fonctionne pas. (avec différentes méthodes à partir du point suivant)
- Cela fonctionnerait probablement, mais j'espère que ce n'est qu'une solution de contournement, pas la solution :(.
- J'ai essayé les fonctions Attach / Add / ChangeObjectState pour BlogPost et / ou Tags dans toutes les combinaisons possibles. Échoué.
- Cela ressemble à ce dont j'ai besoin, mais cela ne fonctionne pas (j'ai essayé de le réparer, mais je ne peux pas pour mon problème).
- J'ai essayé ChangeState / Add / Attach / ... les objets de relation du contexte. Échoué.
«Ne fonctionne pas» signifie dans la plupart des cas que j'ai travaillé sur la «solution» donnée jusqu'à ce qu'elle ne produise aucune erreur et enregistre au moins les propriétés de BlogPost. Ce qui se passe avec les relations varie: généralement, les balises sont ajoutées à nouveau à la table des balises avec de nouveaux PK et le BlogPost enregistré fait référence à celles-ci et non à celles d'origine. Bien sûr, les balises renvoyées ont des PK, et avant les méthodes de sauvegarde / mise à jour, je vérifie les PK et ils sont égaux à ceux de la base de données, donc EF pense probablement qu'il s'agit de nouveaux objets et que ces PK sont ceux temporaires.
Un problème que je connais et qui pourrait rendre impossible la recherche d'une solution simple automatisée: lorsque la collection d'un objet POCO est modifiée, cela devrait se produire par la propriété de collection virtuelle mentionnée ci-dessus, car alors l'astuce FixupCollection mettra à jour les références inversées à l'autre extrémité de la relation plusieurs-à-plusieurs. Cependant, lorsqu'une vue «renvoie» un objet BlogPost mis à jour, cela ne se produit pas. Cela signifie qu'il n'y a peut-être pas de solution simple à mon problème, mais cela me rendrait très triste et je détesterais le triomphe EF4-POCO-MVC :(. Cela signifierait également qu'EF ne peut pas faire cela dans l'environnement MVC, quel que soit le cas Les types d'objets EF4 sont utilisés: (. Je pense que le suivi des modifications basé sur les instantanés devrait découvrir que le BlogPost modifié a des relations avec des balises avec des PK existants.
Btw: Je pense que le même problème se produit avec les relations un-à-plusieurs (google et mon collègue le disent). Je vais essayer à la maison, mais même si cela fonctionne, cela ne m'aide pas dans mes six relations plusieurs à plusieurs dans mon application :(.
la source
Réponses:
Essayons de cette façon:
Éditer:
Je suppose que l'un de mes commentaires vous a donné de faux espoirs qu'EF fera la fusion pour vous. J'ai beaucoup joué avec ce problème et ma conclusion dit qu'EF ne le fera pas pour vous. Je pense que vous avez également trouvé ma question sur MSDN . En réalité, de telles questions sont nombreuses sur Internet. Le problème est qu'il n'est pas clairement indiqué comment gérer ce scénario. Alors jetons un œil sur le problème:
Contexte du problème
EF doit suivre les modifications sur les entités afin que la persistance sache quels enregistrements doivent être mis à jour, insérés ou supprimés. Le problème est qu'il est de la responsabilité d'ObjectContext de suivre les modifications. ObjectContext est capable de suivre les modifications uniquement pour les entités attachées. Les entités créées en dehors de ObjectContext ne sont pas du tout suivies.
Description du problème
Sur la base de la description ci-dessus, nous pouvons clairement affirmer que EF est plus adapté aux scénarios connectés où l'entité est toujours attachée au contexte - typique pour une application WinForm. Les applications Web nécessitent un scénario déconnecté dans lequel le contexte est fermé après le traitement de la demande et le contenu de l'entité est passé en tant que réponse HTTP au client. La prochaine requête HTTP fournit le contenu modifié de l'entité qui doit être recréé, attaché à un nouveau contexte et conservé. La récréation se produit généralement en dehors de la portée du contexte (architecture en couches avec persistance ignorée).
Solution
Alors, comment faire face à un tel scénario déconnecté? Lorsque vous utilisez les classes POCO, nous avons 3 façons de gérer le suivi des modifications:
La synchronisation manuelle sur une seule entité est une tâche facile. Il vous suffit d'attacher une entité et d'appeler AddObject pour l'insertion, DeleteObject pour la suppression ou définir l'état dans ObjectStateManager sur Modified pour la mise à jour. La vraie douleur survient lorsque vous devez gérer un graphique d'objets au lieu d'une seule entité. Cette douleur est encore pire lorsque vous avez affaire à des associations indépendantes (celles qui n'utilisent pas la propriété de clé étrangère) et de nombreuses à plusieurs relations. Dans ce cas, vous devez synchroniser manuellement chaque entité dans le graphe d'objets mais aussi chaque relation dans le graphe d'objets.
La synchronisation manuelle est proposée comme solution par la documentation MSDN: Attacher et détacher des objets dit:
Les méthodes mentionnées sont ChangeObjectState et ChangeRelationshipState de ObjectStateManager = suivi manuel des modifications. Une proposition similaire se trouve dans un autre article de documentation MSDN: Defining and Managing Relationships dit:
De plus, il y a un article de blog lié à EF v1 qui critique exactement ce comportement d'EF.
Raison de la solution
EF a de nombreuses opérations et paramètres "utiles" tels que Refresh , Load , ApplyCurrentValues , ApplyOriginalValues , MergeOption, etc. Je préfère ne pas tester ces méthodes avec des types complexes imbriqués dans entity.
Autre solution proposée
Au lieu d'une véritable fonctionnalité de fusion, l'équipe EF fournit quelque chose appelé Entités d'auto-suivi (STE) qui ne résolvent pas le problème. Tout d'abord, STE ne fonctionne que si la même instance est utilisée pour l'ensemble du traitement. Dans une application Web, ce n'est pas le cas, sauf si vous stockez l'instance dans un état d'affichage ou une session. En raison de cela, je suis très mécontent d'utiliser EF et je vais vérifier les fonctionnalités de NHibernate. La première observation dit que NHibernate a peut-être une telle fonctionnalité .
Conclusion
Je terminerai ces hypothèses avec un lien unique vers une autre question connexe sur le forum MSDN. Vérifiez la réponse de Zeeshan Hirani. Il est l'auteur de Recettes Entity Framework 4.0 . S'il dit que la fusion automatique des graphiques d'objets n'est pas prise en charge, je le crois.
Mais il est toujours possible que je me trompe complètement et que certaines fonctionnalités de fusion automatique existent dans EF.
Modifier 2:
Comme vous pouvez le voir, cela a déjà été ajouté à MS Connect en tant que suggestion en 2007. MS l'a fermé comme quelque chose à faire dans la prochaine version, mais en réalité rien n'avait été fait pour améliorer cet écart, sauf STE.
la source
J'ai une solution au problème décrit ci-dessus par Ladislav. J'ai créé une méthode d'extension pour le DbContext qui effectuera automatiquement l'ajout / la mise à jour / la suppression en fonction d'un diff du graphique fourni et du graphique persistant.
Veuillez jeter un œil et voir si cela peut aider http://refactorthis.wordpress.com/2012/12/11/introducing-graphdiff-for-entity-framework-code-first-allowing-automated-updates-of-a- graphe d'entités détachées /
Vous pouvez accéder directement au code ici https://github.com/refactorthis/GraphDiff
la source
Je sais qu'il est tard pour l'OP, mais comme c'est un problème très courant, j'ai publié ceci au cas où cela servirait quelqu'un d'autre. J'ai joué avec ce problème et je pense que j'ai une solution assez simple, ce que je fais est:
Dans l'exemple suivant, "dataobj" et "_categories" sont les paramètres reçus par mon contrôleur "dataobj" est mon objet principal et "_categories" est un IEnumerable contenant les ID des catégories sélectionnées par l'utilisateur dans la vue.
Cela fonctionne même pour plusieurs relations
la source
L'équipe Entity Framework est consciente qu'il s'agit d'un problème d'utilisabilité et prévoit de le résoudre après EF6.
De l'équipe Entity Framework:
Si cela vous concerne, votez pour la fonctionnalité à
http://entityframework.codeplex.com/workitem/864
la source
Toutes les réponses étaient excellentes pour expliquer le problème, mais aucune n'a vraiment résolu le problème pour moi.
J'ai trouvé que si je n'utilisais pas la relation dans l'entité parente, mais que je venais d'ajouter et de supprimer les entités enfants, tout fonctionnait très bien.
Désolé pour le VB mais c'est ce dans quoi le projet sur lequel je travaille est écrit.
L'entité parente "Report" a une relation un à plusieurs avec "ReportRole" et a la propriété "ReportRoles". Les nouveaux rôles sont transmis par une chaîne séparée par des virgules à partir d'un appel Ajax.
La première ligne supprimera toutes les entités enfants, et si j'utilisais "report.ReportRoles.Remove (f)" au lieu de "db.ReportRoles.Remove (f)" j'obtiendrais l'erreur.
la source