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

Entity Framework Discussion :

Insérer un nouvel objet dans une relation 1 : n (avec une procédure stockée) [Débutant]


Sujet :

Entity Framework

  1. #1
    Membre à l'essai
    Inscrit en
    Mai 2007
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 31
    Points : 12
    Points
    12
    Par défaut Insérer un nouvel objet dans une relation 1 : n (avec une procédure stockée)
    Bonjour.

    Je me permet de solliciter votre aide au sujet du problème suivant.
    Lorsque j'essaie de faire une insertion d'un objet avec un ou plusieurs objet enfants associés j'obtiens une erreur FOREIGN KEY CONSTRAINT.

    Voici le MLD simplifié de l'application.

    Produit(id, nom, emplacement)
    Article(id, id_produit, nom, numserie)

    Je souhaite insérer un produit qui n'existe pas encore ainsi qu'un ou plusieurs articles associés. Voici un extrait du code.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    private void AjouterArticle()
            {
                this.CurrentProduit = new Produit();
                Random rand = new Random();
                this.CurrentProduit.article.Add(new article { numserie = rand.Next(1000).ToString() });
            }
     
    public void AjouterProduit()
            {
              this.DomainContext.produits.Add((produit)parameter);
              this.DomainContext.SubmitChanges(this.OnSubmitionCompleted, null);
            }
    A noter que si le produit existe déjà celà ne pose aucun problème.
    En effet, lorsque l'objet viens d'être instancié l'id du produit est toujours fixé à 0. Effectivement, dans les requêtes SQL, EF essai d'insérer un enregistrement dans la table article avec un id_produit à 0.

    Je me suis également assuré que l'attribut StoreGeneratedPattern="Identity" ait bien été spécifié dans le document SSDL du modèle.

    J'avoue que je ne sais plus ou chercher.

    Toute aide sera grandement appréciée.
    Merci d'avance !

  2. #2
    Membre habitué
    Homme Profil pro
    Inscrit en
    Avril 2013
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2013
    Messages : 76
    Points : 143
    Points
    143
    Par défaut
    Essaie de sauvegarder les changements en base de données entre la création du produit et la liaisons produit/article.

    Au moment ou tu enregistre le produit, EF lui renseignera son id.

  3. #3
    Membre à l'essai
    Inscrit en
    Mai 2007
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 31
    Points : 12
    Points
    12
    Par défaut
    Bonsoir.

    Dans mon esprit j'avais cru comprendre que l'on pouvait insérer des objets nouveaux avec des objets enfants tous d'un coup en même temps.

    Je vais essayé de faire comme vous me l'avez suggéré.

    Merci !

  4. #4
    Membre habitué
    Homme Profil pro
    Inscrit en
    Avril 2013
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2013
    Messages : 76
    Points : 143
    Points
    143
    Par défaut
    En fait, ça doit dépendre du sens dans lequel tu fais tes relations.

    Tu ajoute tes articles au produits. Donc, il doit chercher a enregistrer l'article avant le produit et c'est là que ça coince.

    Si cette liaison tu l'as prends dans l'autre sens pour la création, il se peut que ça se passe mieux. Tu ajoute ton produit aux différent articles.

    Mais si tu ne veux pas t’embêter tu enregistrer ton produit avant de l'utiliser.

  5. #5
    Membre à l'essai
    Inscrit en
    Mai 2007
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 31
    Points : 12
    Points
    12
    Par défaut
    Bonjour.

    Comme celà ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    this.CurrentProduit.article.Add(new article { produit = this.CurrentProduit, numserie = rand.Next(1000).ToString() });
    Pour le moment, je part sur l'autre piste mais il est toujours intéressant de savoir s'il est possible de faire autrement et de comparer.
    Personnellement, ça m'arrangerait si ça fonctionne. Ça m'éviterais de faire des collections intermédiaires pour ensuite les intégrer dans mon produit après création.

    EDIT :

    J'ai essayé de créer le produit au préalable mais cela ne semble pas fonctionner. L'identifiant ne s'actualise pas même en rafraîchissant les données.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    public void AjouterProduit(object parameter)
    {
        this.DomainContext.produits.Add((produit)parameter);
        this.DomainContext.SubmitChanges(this.OnProduitCreated, false);
    }
     
    private void OnProduitCreated(SubmitOperation so)
    {
        if (so.HasError) { this.OnSubmitionCompleted(so); return; }
        this.DomainContext.Load<produit>(this.DomainContext.GetProduitQuery().Where<produit>(p => p.numproduit == this.CurrentProduit.numproduit))
            .Completed += (s, e) =>
                {
                    foreach (article article in this.ArticlesCollection)
                    {
                        this.CurrentProduit.article.Add(article);
                    }
     
                    this.DomainContext.SubmitChanges(this.OnSubmitionCompleted, true);
                };
    }
    En tout cas merci de prêter attention à mon problème !

  6. #6
    Membre habitué
    Homme Profil pro
    Inscrit en
    Avril 2013
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2013
    Messages : 76
    Points : 143
    Points
    143
    Par défaut
    Citation Envoyé par Binenebi Voir le message
    Bonjour.

    Comme celà ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    this.CurrentProduit.article.Add(new article { produit = this.CurrentProduit, numserie = rand.Next(1000).ToString() });
    Pour le moment, je part sur l'autre piste mais il est toujours intéressant de savoir s'il est possible de faire autrement et de comparer.
    C'est à ça que je pensais. Si j'ai bien compris ton modèle, ce sera parfaitement équivalent en base de données.


    Citation Envoyé par Binenebi Voir le message
    J'ai essayé de créer le produit au préalable mais cela ne semble pas fonctionner. L'identifiant ne s'actualise pas même en rafraîchissant les données.
    En fait, j'ai penser que tu passais par un DbContext classique, j'ai pas tiquer sur le SubmitChanges

    Apparemment tu passe par les services RIA, donc en effet ton objet ne sera pas modifié (donc pas d'ID). Tu doit pouvoir récupérer ton nouveau produit de cette façon:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    private void OnProduitCreated(SubmitOperation so)
    {
    	EntityChangeSet changeSet = this.DomainContext.produits.GetChanges();
    	if(changeSet.AddedEntities.Count == 1)
    	{
    		this.CurrentProduit = changeSet.AddedEntities.First();
    		/*
    			...
    		*/
    	}
    }
    Ici, on est sur la condition ou il n'y a qu'un produit créer à la fois par l'application et que tu n'ai pas un autre utilisateur qui créer aussi un produit entre ton SubmitChanges et le GetChanges?

  7. #7
    Membre à l'essai
    Inscrit en
    Mai 2007
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 31
    Points : 12
    Points
    12
    Par défaut
    Bonjour.
    Autant pour moi je n'ai pas précisé ce que j'utilisais dans mon premier post.

    En revanche, je n'ai pas la méthode GetChanges().

    Ceci dit, j'ai refait un essai en créant un nouveau projet.
    Le code suivant fonctionne parfaitement.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    this.CurrentProduit.article.Add(new article { produit = this.CurrentProduit, numserie = rand.Next(1000).ToString() });
    La seul différence avec le projet initial c'est que je n'ai pas mappé de procédure stockée sur " l'insert " de ma classe produit dans mon modèle edmx.

    Donc dans ce cas comment EntityFramework est censé récupéré l'id lorsque l'insert se fait avec une procédure stockée alors qu'il y arrive parfaitement bien en attaquant la table directement ?
    A noter qu'en production je dois absolument utiliser cette procédure :/.

  8. #8
    Membre habitué
    Homme Profil pro
    Inscrit en
    Avril 2013
    Messages
    76
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2013
    Messages : 76
    Points : 143
    Points
    143
    Par défaut
    D'accord, je comprends mieux.

    Il faut que ta procédure stockée puisse retournée l'id qui a été insérer et que tu bind cette colonne du resultat sur ta propriété ID.

    Cet article te permettra surement d'y voir plus clair :
    http://learnentityframework.com/Lear...ty-data-model/

    (Au moins avec les captures)


    Après pour récupérer l'id générée (dans ta ps),tu peux faire un
    (dernier ID généré durant la connection)
    ou

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT IDENT_CURRENT('maTable')
    (dernier Id généré pour une table spécifique, possible de récupérer un id généré par une autre connection par contre).

  9. #9
    Membre à l'essai
    Inscrit en
    Mai 2007
    Messages
    31
    Détails du profil
    Informations forums :
    Inscription : Mai 2007
    Messages : 31
    Points : 12
    Points
    12
    Par défaut
    Ça fonctionne !

    Merci ! Vu l'impasse dans laquelle j'étais, j'apprécie vraiment votre aide !
    Je n'avais pas du tout pensé au binding sur le retour des procédures.
    Heureusement, je peux modifier les procédures en questions.

    En revanche, au cas où je n'aurais pas accès à toutes les procédures pour pouvoir les modifier et rajouter une instruction pour retourner l'id sur le sortie standard j'ai pensé à la chose suivante.

    Créer une procédure qui appel la procédure d'origine et qui retourne l'id.

    Je pense que ça serait plus simple que d'essayer de bricoler EF en rafraichissant les données trop souvent.

  10. #10
    Membre expert Avatar de iberserk
    Homme Profil pro
    Architecte de base de données
    Inscrit en
    Novembre 2004
    Messages
    1 795
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Architecte de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2004
    Messages : 1 795
    Points : 3 173
    Points
    3 173
    Par défaut
    Attention ceci est une grosse erreur:
    @@IDENTITY retourne la dernière valeur identité de la table... mais pas forcemment celle que VOUS venez d'insérer via votre PS...

    Il faut utiliser @@SCOPE_IDENTITY:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Select @@SCOPE_IDENTITY
    Msdn:
    @@IDENTITY et SCOPE_IDENTITY retournent la dernière valeur d'identité générée dans une table au cours de la session en cours. Toutefois, SCOPE_IDENTITY retourne uniquement la valeur à l'intérieur de la portée actuelle ; @@IDENTITY n'est pas limitée à une portée spécifique.
    Prendre conscience, c'est transformer le voile qui recouvre la lumière en miroir.
    MCTS Database Development
    MCTS Database Administration

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 01/05/2009, 15h41
  2. Réponses: 3
    Dernier message: 27/06/2008, 15h06
  3. Réponses: 1
    Dernier message: 23/11/2007, 12h04
  4. Ajout nouvel objet dans JList
    Par sorry60 dans le forum Composants
    Réponses: 2
    Dernier message: 09/12/2006, 22h37
  5. [JNDI] comment insérer de nouveaux objets dans notre annuaire LDAP
    Par julien1981 dans le forum API standards et tierces
    Réponses: 6
    Dernier message: 23/06/2006, 15h07

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