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

ASP.NET Discussion :

Problème de récupération de données avec une relation many to many (.Net Core Razor pages + EFCore 5)


Sujet :

ASP.NET

  1. #1
    Candidat au Club
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Février 2019
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Février 2019
    Messages : 2
    Points : 3
    Points
    3
    Par défaut Problème de récupération de données avec une relation many to many (.Net Core Razor pages + EFCore 5)
    Bonjour,

    Je développe un site en .Net Razor pages avec Entity framework Core 5 et j'essaye de comprendre comment récupérer automatiquement les données de mon formulaire (model binding) quand on a une propriété issus d'une relation many to many (sans entité intermédiaire).

    Par exemple si j'ai une entité Voiture et une entité Pièce avec la relation : une voiture a plusieurs pièces et une pièce est utilisée sur plusieurs voitures.

    Si j'ai bien compris, depuis EFCore 5 il y a 2 façons de créer cette relation many to many :
    soit avec une entité intermédiaire : Voiture - PieceVoiture - Piece
    soit seulement avec les deux entités concernées : Voiture - Piece

    Dans le premier cas je n'ai pas de soucis de récupération de données :

    Coté entités :

    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 class Voiture
        {
            public int VoitureId { get; set; }
            public string Nom { get; set; }
            public List<PieceVoiture> Pieces { get; set; }
        }
     
        public class Piece
        {
            public int PieceId { get; set; }
            public string Reference { get; set; }
            public List<PieceVoiture> Voitures { get; set; }
        }
     
       public class PieceVoiture
        {
            public int VoitureId { get; set; }
            public int PieceId { get; set; }
            public Voiture Voiture { get; set; }
            public Piece Piece { get; set; }
        }
    Coté Razor pages :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    [BindProperty]
    public Voiture Voiture {get; set;}
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <select name="Voiture.Pieces[i].PieceId"> ... </select>
    il me suffit de construire mes listes déroulantes avec cette propriété name pour que les éléments sélectionnés soit automatiquement assignés à la propriété Pieces de mon modèle.

    Dans le deuxième cas, cela ne fonctionne pas.

    Coté entités :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
        public class Voiture
        {
            public int Id { get; set; }
            public string Nom { get; set; }
            public List<Piece> Pieces { get; set; }
        }
     
        public class Piece
        {
            public int Id { get; set; }
            public string Reference { get; set; }
            public List<Voiture> Voitures { get; set; }
        }
    Coté Razor pages :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <select name="Voiture.Pieces[i].PieceId"> ... </select>
    Je n'arrive pas à trouver ce que je dois renseigner dans la propriété name pour que cela fonctionne. Selon mes essais (Voiture.Pieces[i].PieceId, Voiture.Pieces[i].PiecesId, Voiture.Pieces[i], etc...) soit il ne se passe rien soit j'ai une exception Sql parce qu'il tente d'ajouter une entrée dans Piece au lieu de PieceVoiture.

    Auriez vous une idée ? Connaîtriez vous des astuces pour débugger ce processus de model binding ?

  2. #2
    Membre du Club
    Homme Profil pro
    Alternant
    Inscrit en
    Octobre 2019
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Jura (Franche Comté)

    Informations professionnelles :
    Activité : Alternant

    Informations forums :
    Inscription : Octobre 2019
    Messages : 48
    Points : 66
    Points
    66
    Par défaut
    Dans un premier temps est-ce que tu fais bien ton Include quand tu vas chercher les données avec ton DbContext ? Ensuite essaye de les passer en ICollection, et pour finir as-tu créer la relation dans le DbContext ?

    De plus écrit tel quel, le code est pris comme étant un texte -> "Voiture.Pieces[i].PieceId" -> "@Voiture.Pieces[i].PieceId"

  3. #3
    Candidat au Club
    Femme Profil pro
    Administrateur de base de données
    Inscrit en
    Février 2019
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données

    Informations forums :
    Inscription : Février 2019
    Messages : 2
    Points : 3
    Points
    3
    Par défaut
    Merci pour ta réponse iR3SH.

    Depuis mon dernier message j'ai remarqué que j'avais fait une erreur d'observation, le model binding n’était pas vraiment le problème, c’était plutôt celui de l'enregistrement des données :

    Le cas où j'obtenais une exception SQL était une bonne piste, pour info c'était celle là : SqlException: Cannot insert explicit value for identity column in table 'Pieces' when IDENTITY_INSERT is set to OFF.
    J'ai remarqué que contrairement à ce que je pensais, le model binding fonctionnait dans ce cas là.

    C’était avec le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <select name="Voiture.Pieces[i].PieceId"> ... </select>
    Le problème c'est que j'étais persuadé que EFCore, connaissant l'entité (Piece) et disposant d'un Id (PieceId), pourrait faire le lien avec ce qui existait en base de données : apparemment non.
    Au lieu de se dire : tu as sélectionné une Piece avec, certes une Reference null (la propriété string pas la reference d'objet) mais un PieceId valide => j'en déduis que tu veux créer une association entre la voiture et cette pièce,
    EFCore déduit : tu veux ajouter en base de données cette Piece sans Reference, en forçant le PieceId.

    A partir de ce constat, j'ai ajouté cette ligne dans mon OnPost() pour que cela fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Voiture.Pieces = ListePieces.Where(x => Voiture.Pieces.Select(p => p.PieceId).Contains(x.PieceId)).ToList();
    Avec cette ligne je récupère les Pieces en base de données correspondant aux pièces sélectionnées dans mon formulaire (via les PieceId) et EFCore comprends enfin qu'il faut créer des liens entre la voiture et ces pièces.

    J'ignore s'il est possible de faire fonctionner EFCore comme dans mon raisonnement initial mais dans l'immédiat c'est la seule solution que j'ai trouvé.

    En résumé : une classe de moins à créer (PieceVoiture) mais une étape de plus à ajouter pour l'enregistrement.

    Pour répondre à ton message :
    - Pas de soucis d'Include dans ce cas vu que Piece ne dépendait pas d'autres objets, je récupérai seulement PieceId et Reference.
    - Pour les ICollection j'avais des soucis d'indexation [] lors de ma création de listes donc j'ai pas trouvé d'autres choix que de les définir en List.
    - Je n'avais pas crée de relations dans le DbContext, j’espérais que cela puisse fonctionner sans dans un premier temps.

    Pour ta dernière remarque tu as raison cela ne pouvait pas fonctionner sans @ par contre vu que je l'utilisais dans une boucle c’était plutôt "Voiture.Pieces[@i].PieceId".

  4. #4
    Membre du Club
    Homme Profil pro
    Alternant
    Inscrit en
    Octobre 2019
    Messages
    48
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Jura (Franche Comté)

    Informations professionnelles :
    Activité : Alternant

    Informations forums :
    Inscription : Octobre 2019
    Messages : 48
    Points : 66
    Points
    66
    Par défaut
    Je peux peut-être t'aider un peu plus car je vois où tu veux en venir et j'ai un projet qui présente des similitudes

    Voilà ce que je te propose de tester ->

    Côter Entité :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    public class Voiture
        {
            public int VoitureId { get; set; }
            public string Nom { get; set; }
            public ICollection<Piece> Pieces { get; set; }
        }
     
        public class Piece
        {
            public int PieceId { get; set; }
            public string Reference { get; set; }
            public ICollection<Voiture> Voitures { get; set; }
        }
    Côter DbContext :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public DbSet<Voiture> Voitures { get; set; }
    public DbSet<Piece> Pieces{ get; set; }
     
    protected override voir OnModelCreating(ModelBuilder modelBuilder)
    {
       modelBuilder.Entity<Voiture>().HasMany(c => c.Pieces).WithMany(e => e.Voiture).IsRequired(); // IsRequired() car par def. une voiture n'existe pas sans pièces
       modelBuilder.Entity<Piece>().HasMany(c => c.Voiture).WithMany(e => e.Piece);
    }
    Quand tu vas chercher tes données :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
       _Dbcontext.Voiture.Include(c => c.Pieces).ToList();
       _Dbcontext.Piece.Include(c => c.Voitures).ToList();
    Le .Include() permet d'aller chercher les données relatives à chaque Objet tu auras donc une list contenant toutes tes pièces ou voitures

Discussions similaires

  1. ajout de données avec une relation N-à-N
    Par yeah_baby64 dans le forum Access
    Réponses: 3
    Dernier message: 28/07/2006, 18h19
  2. [D6 => XML] Récupération de données avec une boucle.
    Par Bason_sensei dans le forum Delphi
    Réponses: 1
    Dernier message: 23/05/2006, 13h50
  3. Réponses: 4
    Dernier message: 09/05/2006, 10h29
  4. Problème de récupérations de données dans une table mysql
    Par Helpine dans le forum SQL Procédural
    Réponses: 3
    Dernier message: 09/03/2006, 19h07
  5. Réponses: 2
    Dernier message: 14/05/2004, 14h32

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