Insérer / mettre à jour plusieurs à plusieurs Entity Framework. Comment fait-on ça?

104

J'utilise EF4 et je suis nouveau. J'ai plusieurs à plusieurs dans mon projet et je n'arrive pas à comprendre comment insérer ou mettre à jour. J'ai construit un petit projet juste pour voir comment il devrait être codé.

Supposons que j'ai 3 tables

  1. Classe: ClassID-ClassName
  2. Étudiant: StudentID-FirstName-Name
  3. StudentClass: StudentID-ClassID

Après avoir ajouté toutes les relations et mis à jour le modèle via le navigateur de modèles, j'ai remarqué que StudentClass n'apparaît pas, cela semble être le comportement par défaut.

Maintenant, je dois faire à la fois une insertion et une mise à jour. Comment faites-vous? Des exemples de code ou un lien où je peux télécharger un exemple, ou pouvez-vous épargner 5 minutes?

user9969
la source

Réponses:

139

En termes d'entités (ou d'objets), vous avez un Classobjet qui a une collection de Studentset un Studentobjet qui a une collection de Classes. Étant donné que votre StudentClasstable ne contient que les Id et aucune information supplémentaire, EF ne génère pas d'entité pour la table de jointure. C'est le comportement correct et c'est ce à quoi vous vous attendez.

Maintenant, lorsque vous faites des insertions ou des mises à jour, essayez de penser en termes d'objets. Par exemple, si vous souhaitez insérer une classe avec deux étudiants, créer l' Classobjet, les Studentobjets, ajouter les étudiants à la Studentscollection de la classe , ajouter l' Classobjet au contexte et appeler SaveChanges:

using (var context = new YourContext())
{
    var mathClass = new Class { Name = "Math" };
    mathClass.Students.Add(new Student { Name = "Alice" });
    mathClass.Students.Add(new Student { Name = "Bob" });

    context.AddToClasses(mathClass);
    context.SaveChanges();
}

Cela créera une entrée dans le Classtableau, deux entrées dans le Studenttableau et deux entrées dans le StudentClasstableau les reliant.

Vous faites essentiellement la même chose pour les mises à jour. Récupérez simplement les données, modifiez le graphique en ajoutant et supprimant des objets des collections, appelez SaveChanges. Consultez cette question similaire pour plus de détails.

Modifier :

Selon votre commentaire, vous devez en insérer un nouveau Classet y ajouter deux existants Students:

using (var context = new YourContext())
{
    var mathClass= new Class { Name = "Math" };
    Student student1 = context.Students.FirstOrDefault(s => s.Name == "Alice");
    Student student2 = context.Students.FirstOrDefault(s => s.Name == "Bob");
    mathClass.Students.Add(student1);
    mathClass.Students.Add(student2);

    context.AddToClasses(mathClass);
    context.SaveChanges();
}

Comme les deux étudiants sont déjà dans la base de données, ils ne seront pas insérés, mais comme ils sont maintenant dans la Studentscollection de Class, deux entrées seront insérées dans la StudentClasstable.

Yakimych
la source
Bonjour, Merci pour votre réponse Mon scénario est que je dois insérer 1 entrée dans la classe et comme x votre exemple 2 entrées dans StudentClass et aucune entrée dans Student.Je ne sais pas comment je le fais
user9969
QUI A FONCTIONNÉ UN TRAITEMENT.En ce qui concerne la mise à jour, est-ce que je dois faire quelque chose de spécial? Par exemple, mettre à jour le nom de classe par exemple.
user9969
3
Cela ajoutera une surcharge de récupération de la base de données les éléments à ajouter. La méthode Attach peut être utilisée pour ajouter uniquement une relation. Voir msdn.microsoft.com/en-us/data/jj592676.aspx et également stackoverflow.com/questions/11355019/...
Gnomo
3
AddToClasses est le DbSet pour la classe?
Jo Smo
1
N'oubliez pas d'initialiser vos collections dans les constructeurs pour Class et Student. Par exemple: public Class () {this.Students = new HashSet <Student> (); }
user1040323
40

Essayez celui-ci pour la mise à jour:

[HttpPost]
public ActionResult Edit(Models.MathClass mathClassModel)
{
    //get current entry from db (db is context)
    var item = db.Entry<Models.MathClass>(mathClassModel);

    //change item state to modified
    item.State = System.Data.Entity.EntityState.Modified;

    //load existing items for ManyToMany collection
    item.Collection(i => i.Students).Load();

    //clear Student items          
    mathClassModel.Students.Clear();

    //add Toner items
    foreach (var studentId in mathClassModel.SelectedStudents)
    {
        var student = db.Student.Find(int.Parse(studentId));
        mathClassModel.Students.Add(student);
    }                

    if (ModelState.IsValid)
    {
       db.SaveChanges();
       return RedirectToAction("Index");
    }

    return View(mathClassModel);
}
Stritof
la source
cela a sauvé ma journée merci !!! leur partie clé étant l'élément. partie
Gerrie Pretorius
Juste une note latérale, j'avais une InvalidOperationException en faisant cela, quelque chose comme mon entité n'existait pas dans le contexte. Je viens d'appeler context.MyEntityCollection.Attach (myEntity) pour y faire face.
Kilazur
Je n'aurais jamais compris cela. Merci beaucoup.
Jared Beach
1
Permettez-moi d'ajouter mes remerciements ici. J'ai écrit et testé plus de 130 lignes de code au cours des 4 derniers jours en essayant d'accomplir cette tâche, mais je n'ai pas pu le faire. J'ai essayé cela et les choses ont parfaitement fonctionné. Bien que je ne comprenne pas le but d'établir la variable d' élément et de ne pas l'utiliser du tout, je suis juste content que cela fonctionne! Merci un million de bajillion !!!! :)
Dude-Dastic
Considérant que la question est Insérer ET Mettre à jour, cette réponse complète la question et la réponse acceptée. Merci beaucoup!
Vahx
5

Je voulais ajouter mon expérience à ce sujet. En effet EF, lorsque vous ajoutez un objet au contexte, il change l'état de tous les enfants et entités associées en Added. Bien qu'il y ait une petite exception dans la règle ici: si les enfants / entités associées sont suivis par le même contexte, EF comprend que ces entités existent et ne les ajoute pas. Le problème se produit lorsque, par exemple, vous chargez les enfants / entités associées à partir d'un autre contexte ou d'une interface utilisateur Web, etc., puis oui, EF ne sait rien de ces entités et les ajoute toutes. Pour éviter cela, il suffit de récupérer les clés des entités et de les trouver (par exemple context.Students.FirstOrDefault(s => s.Name == "Alice"))dans le même contexte dans lequel vous voulez faire l'addition.

Athina
la source
3

J'utilise la méthode suivante pour gérer la relation plusieurs-à-plusieurs où seules les clés étrangères sont impliquées.

Donc pour l' insertion :

public void InsertStudentClass (long studentId, long classId)
{
    using (var context = new DatabaseContext())
    {
        Student student = new Student { StudentID = studentId };
        context.Students.Add(student);
        context.Students.Attach(student);

        Class class = new Class { ClassID = classId };
        context.Classes.Add(class);
        context.Classes.Attach(class);

        student.Classes = new List<Class>();
        student.Classes.Add(class);

        context.SaveChanges();
    }
}

Pour supprimer ,

public void DeleteStudentClass(long studentId, long classId)
{
    Student student = context.Students.Include(x => x.Classes).Single(x => x.StudentID == studentId);

    using (var context = new DatabaseContext())
    {
        context.Students.Attach(student);
        Class classToDelete = student.Classes.Find(x => x.ClassID == classId);
        if (classToDelete != null)
        {
            student.Classes.Remove(classToDelete);
            context.SaveChanges();
        }
    }
}
lenglei
la source
1

Dans le cadre d'entité, lorsqu'un objet est ajouté au contexte, son état passe à Ajouté. EF modifie également l'état de chaque objet pour être ajouté dans l'arborescence d'objets et, par conséquent, vous obtenez une erreur de violation de clé primaire ou des enregistrements en double sont ajoutés dans la table.

Nilesh Hirapra
la source
2
Veuillez modifier pour donner suffisamment de détails afin qu'un utilisateur n'ait pas à visiter votre blog pour obtenir la réponse.