IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Accès aux données Discussion :

The relationship between the two objects cannot be defined because they are attached to different ObjectContex


Sujet :

Accès aux données

  1. #1
    Membre du Club
    Inscrit en
    Décembre 2006
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 93
    Points : 55
    Points
    55
    Par défaut The relationship between the two objects cannot be defined because they are attached to different ObjectContex
    Bonjour,
    Je souhaite ajouter une relation entre deux objets d'une base de données en EDMX.
    Mon problème semble relativement simple :

    J'ai un premier objet chargé ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    BD = new MonModeleEDMX();
    ObjetTable1 = from l in BD.Table1
                        where l.IdT1 == IdT1)
                        select l;
    Puis un autre objet chargé dans une autre fonction ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    BD = new MonModeleEDMX();
    ObjetTable2 = from l in BD.Table2
                        where l.IdT2 == IdT2)
                        select l;
    Il existe une table d'association (relation NN) entre Table1 et Table2.
    Je souhaite donc créer une nouvelle association entre ces deux objets.
    J'ai essayé ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ObjetTable1.Table2.Add(ObjetTable2);
    mais j'obtiens le message d'erreur suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects.
    Puis ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    ObjetTable2.BD.Detach(ObjetTable1);
    --> The object cannot be detached because it is not attached to the ObjectStateManager.
     
    ObjetTable1.BD.AttachTo(ObjetTable2.IdT2.ToString(), ObjetTable2);
    --> The EntitySet name 'GestionAssociationEntities.13' could not be found.
    J'avoue ne pas trop comprendre ni ce qui se passe ni ce que je dois faire.

    Merci d'avance.

  2. #2
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Points : 2 202
    Points
    2 202
    Par défaut
    Tu as créé deux contextes donc c'est assez logiques que pour des motifs d'états et de concurrence un contexte ne puisse pas modifier ou agir sur les entités attachées à un autre objet.




    Expose ton context via un singleton et tu devrais vite voir le résultat changer.
    Le pb est là :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    BD = new MonModeleEDMX();
    Tu verras d'ailleurs que soit tu utilises :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    BD = new MonModeleEDMX();
    ObjetTable1 = from l in BD.Table1
                        where l.IdT1 == IdT1)
                        select l;
    ObjetTable2 = from l in BD.Table2
                        where l.IdT2 == IdT2)
                        select l;
    ObjetTable1.Table2.Add(ObjetTable2);
    Ton pb va disparaitre.

    Il s'agit là de comprendre un autre pattern important à l'ORM : Unit of Work

    Là.

  3. #3
    Membre du Club
    Inscrit en
    Décembre 2006
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 93
    Points : 55
    Points
    55
    Par défaut
    Merci pour la réponse,
    Je pense que mon problème vient clairement d'un problème quant à l'utilisation du contexte.

    En fait mes deux objets Table1 et Table2 ne sont pas gérés au même niveau, ce qui explique pourquoi je ne les ai pas chargé avec le même contexte.

    J'avais volontairement simplifié un peu le problème.
    En réalité je charge une liste d'objets de Table2 via un Web service.
    Puis via l'application l'utilisateur sélectionne un élément de la liste.

    C'est pour cette raison que je souhaitais enlever l'objet Table2 de son contexte pour l'ajouter au contexte de Table1.

    Mais j'ai peut-être une autre solution qui est de passer en paramètre mon contexte (MonModeleEDMX) en paramètre à mon Web Service.
    En fait, je ne sais pas exactement à quel niveau je dois gérer mon contexte. Est-ce au niveau des objets ou au niveau de la page web ?
    Ou alors je me trompe complètement.

    Merci d'avance.

  4. #4
    Membre du Club
    Inscrit en
    Décembre 2006
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 93
    Points : 55
    Points
    55
    Par défaut
    Que pensez-vous notamment du fait de mettre le contexte (MonModeleEDMX()) directement en session ?
    Si c'est mal, en quoi est-ce mal ?

  5. #5
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Points : 2 202
    Points
    2 202
    Par défaut
    En session de quoi ?

    WCF ? ASP.Net ?

    Moi je crois qu'EF doit être utilisé avec des services et chaque service doit réaliser sa propre transaction. Pour le moment, ça me parait compliqué de gérer des conversations.

    Ce qui est mal d'une façon générale c'est de faire des sessions longues, quelque soit l'ORM : cela peut poser des problèmes en légion.
    Il faut donc faire court prècis, et dans la majeure partie des cas utiliser les transactions et le Using pour disposer correctement.

  6. #6
    Membre du Club
    Inscrit en
    Décembre 2006
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 93
    Points : 55
    Points
    55
    Par défaut
    Je suis en ASP.Net,

    La liste des objets de la Table2 est utilisée pour remplir un GridView.
    Elle est concervée en mémoire comme DataSource du GridView sur lequel je peux faire des actions qui vont "taguer" les objets de la liste. Il serait peut-être déjà bien à ce niveau de fermer le contexte de la liste qui de toute façon n'est là que pour de l'affichage. Dois-je faire un Dispose ou autre chose ?

    Puis l'utilisateur valide le formulaire et là tous les objets "tagués" de la liste vont être ajoutés à la liste des objets Table2 rattachés à l'objet de la Table1.

    Entre temps il y a bien entendu eu plusieurs postback.

    Actuellement dans mon code j'ouvre le contexte au chargement d'un objet ou d'une liste que je ne ferme jamais car je n'avais pas encore pris le temps de me poser la question du quand et du comment.

    J'ai donc un contexte au chargement de la liste Table2 et un contexte au chargement de l'objet Table1.
    Entre temps l'utilisateur va faire plusieurs postback, puis faire sa validation.
    Ayant toujours les contextes (depuis sans doute trop longtemps déjà), j'ai juste à faire ma sauvegarde, mais arrive le problème évoqué.

    Et ça m'embeterait de devoir recharger les objets Table2 juste pour les ajouter à Table1 sachant que je les ai déjà en mémoire.

  7. #7
    Rédacteur
    Avatar de Thomas Lebrun
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    9 161
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 9 161
    Points : 19 434
    Points
    19 434
    Par défaut
    Essaye:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    BD = new MonModeleEDMX();
    ObjetTable1 = from l in BD.Table1
                        where l.IdT1 == IdT1)
                        select l;Puis un autre objet chargé dans une autre fonction 
     
    ObjetTable2 = from l in BD.Table2
                        where l.IdT2 == IdT2)
                        select l;
     
    ObjetTable1.Table2.Add(ObjetTable2);

  8. #8
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Points : 2 202
    Points
    2 202
    Par défaut
    Citation Envoyé par Thomas Lebrun Voir le message
    Essaye:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    BD = new MonModeleEDMX();
    ObjetTable1 = from l in BD.Table1
                        where l.IdT1 == IdT1)
                        select l;Puis un autre objet chargé dans une autre fonction 
     
    ObjetTable2 = from l in BD.Table2
                        where l.IdT2 == IdT2)
                        select l;
     
    ObjetTable1.Table2.Add(ObjetTable2);
    Je lui ai déjà dit ça, mais c'est pas ça sa question.
    En fait c'est même faux ce qu'on lui donne puisqu'en fait il faut qu'il..

    - Atomise tous ses traitements en base
    - Utiliser un context et le disposer en fin

    Bref, il faut que tu construises tes accès comme des services.

    Il faut accepter de devoir éventuellement attacher et détacher les entités et surtout ne jamais avoir n contextes concurrents : ce serait la mort du petit cheval.

    Regardes là, ça te donnera plus de pistes :
    EF singleton+context

  9. #9
    Membre du Club
    Inscrit en
    Décembre 2006
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 93
    Points : 55
    Points
    55
    Par défaut
    Bonjour Thomas,
    Merci mais cela ne répond pas vraiment à mon besoin, comme je l'ai expliqué plus haut le but de ma question est de mieux comprendre comme gérer les contexte.
    Voir le post que j'ai mis ce matin à 9h25 pour les détails.

  10. #10
    Membre du Club
    Inscrit en
    Décembre 2006
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 93
    Points : 55
    Points
    55
    Par défaut
    Je vais faire quelques tests cet après-midi pour mieux comprendre.
    En gros l'idée serait de faire un service qui me renvoi un contexte à la demande.

    S'il s'agit d'une requete servant à charger des données qui ne seront pas modifié alors je le ferme immédiatement après avoir exécuté la requete.

    S'il s'agit d'une donnée pouvant être sauvegardée je garde le contexte en session jusqu'à la sauvegarde.

    Si je dois ajouter une relation NN en provenance de ma liste (donc la cas que j'ai évoqué plus tôt) il me faudrait pouvoir ajouter les objets de la liste (contexte fermé)... et c'est là que je ne sais pas encore comme faire et que je risque de rencontrer les problèmes déjà cité plus haut. Concernant le premier paramètre de AttachTo par exemple.. je ne sais pas quoi mettre. Et la fonction Attach ne veut pas prendre mon ObjetTable2.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    ObjetTable2.BD.Detach(ObjetTable1);
    --> The object cannot be detached because it is not attached to the ObjectStateManager.
     
    ObjetTable1.BD.AttachTo(ObjetTable2.IdT2.ToString(), ObjetTable2);
    --> The EntitySet name 'GestionAssociationEntities.13' could not be found.

  11. #11
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Points : 2 202
    Points
    2 202
    Par défaut
    Citation Envoyé par cfeltz Voir le message
    Je vais faire quelques tests cet après-midi pour mieux comprendre.
    En gros l'idée serait de faire un service qui me renvoi un contexte à la demande.

    S'il s'agit d'une requete servant à charger des données qui ne seront pas modifié alors je le ferme immédiatement après avoir exécuté la requete.

    S'il s'agit d'une donnée pouvant être sauvegardée je garde le contexte en session jusqu'à la sauvegarde.

    Si je dois ajouter une relation NN en provenance de ma liste (donc la cas que j'ai évoqué plus tôt) il me faudrait pouvoir ajouter les objets de la liste (contexte fermé)... et c'est là que je ne sais pas encore comme faire et que je risque de rencontrer les problèmes déjà cité plus haut. Concernant le premier paramètre de AttachTo par exemple.. je ne sais pas quoi mettre. Et la fonction Attach ne veut pas prendre mon ObjetTable2.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    ObjetTable2.BD.Detach(ObjetTable1);
    --> The object cannot be detached because it is not attached to the ObjectStateManager.
     
    ObjetTable1.BD.AttachTo(ObjetTable2.IdT2.ToString(), ObjetTable2);
    --> The EntitySet name 'GestionAssociationEntities.13' could not be found.
    D'où le lien que je t'ai envoyé. L'idée est de créer un service pour exposer les contextes.

  12. #12
    Membre du Club
    Inscrit en
    Décembre 2006
    Messages
    93
    Détails du profil
    Informations forums :
    Inscription : Décembre 2006
    Messages : 93
    Points : 55
    Points
    55
    Par défaut
    Oui merci,
    J'ai donc réussi à faire mon ajout. Il m'a suffit de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    MonModeleEDMXLectureDeLaListe.Detach(ObjetTable2);
    MonModeleEDMXEcriture.Attach((IEntityWithKey)ObjetTable1);
    ObjetTable1.Table2.Add(ObjetTable2)
    MonModeleEDMXEcriture.SaveChanges();
    Et pour la suppression j'ai essayé de la même manière (donc sans charger la liste des ObjetsTable2 correspondant à mon ObjetTable1).
    En remplaçant ObjetTable1.Table2.Add(ObjetTable2) par ObjetTable1.Table2.Remove(ObjetTable2). Mais la suppression n'a pas été effective.
    Peut-être est-ce normal.
    Merci en tout cas pour tout.

  13. #13
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Points : 2 202
    Points
    2 202
    Par défaut
    Citation Envoyé par cfeltz Voir le message
    Merci en tout cas pour tout.
    Pas de quoi, bon courage.

  14. #14
    Membre chevronné
    Profil pro
    Inscrit en
    Février 2005
    Messages
    1 273
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 1 273
    Points : 2 202
    Points
    2 202
    Par défaut
    Citation Envoyé par cfeltz Voir le message

    Et pour la suppression j'ai essayé de la même manière (donc sans charger la liste des ObjetsTable2 correspondant à mon ObjetTable1).
    En remplaçant ObjetTable1.Table2.Add(ObjetTable2) par ObjetTable1.Table2.Remove(ObjetTable2). Mais la suppression n'a pas été effective.
    Peut-être est-ce normal.

    Merci en tout cas pour tout.
    Ben oui en fait : tu ne peux pas faire ça, même si tu l'attaches, objetTable1 ne contient pas d'objet ==objettable2, mais un autre.

    Là il faudrait que tu bidouilles l'IEquatable l'entity key, ou que tu passes par un itérateur, ou du linq.

    Good luck !

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 27/07/2010, 09h04
  2. Réponses: 1
    Dernier message: 22/04/2010, 12h24
  3. Réponses: 3
    Dernier message: 10/08/2009, 15h14
  4. Réponses: 9
    Dernier message: 19/11/2008, 08h17
  5. Réponses: 15
    Dernier message: 22/07/2008, 14h24

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo