Inserisci / Aggiorna molti a molti Entity Framework. Come lo faccio?


104

Sto usando EF4 e nuovo. Ho molti a molti nel mio progetto e non riesco a capire come inserirli o aggiornarli. Ho costruito un piccolo progetto solo per vedere come dovrebbe essere codificato.

Supponiamo che io abbia 3 tavoli

  1. Classe: ClassID-ClassName
  2. Studente: StudentID-FirstName-Cognome
  3. StudentClass: StudentID-ClassID

Dopo aver aggiunto tutte le relazioni e aggiornato il modello tramite il browser del modello, ho notato che StudentClass non appare, questo sembra essere il comportamento predefinito.

Ora devo fare sia un inserimento che un aggiornamento. Come si fa? Eventuali esempi di codice o link da cui posso scaricare un esempio o potete risparmiare 5 minuti?

Risposte:


139

In termini di entità (o oggetti) hai un Classoggetto che ha una raccolta di Studentse un Studentoggetto che ha una raccolta di Classes. Poiché la tua StudentClasstabella contiene solo gli ID e nessuna informazione aggiuntiva, EF non genera un'entità per la tabella di unione. Questo è il comportamento corretto ed è quello che ti aspetti.

Ora, quando esegui inserimenti o aggiornamenti, prova a pensare in termini di oggetti. Ad esempio, se vuoi inserire una classe con due studenti, crea l' Classoggetto, gli Studentoggetti, aggiungi gli studenti alla Studentscollezione della classe aggiungi l' Classoggetto al contesto e chiama 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();
}

Questo creerà una voce nella Classtabella, due voci nella Studenttabella e due voci nella StudentClasstabella collegandole insieme.

Fondamentalmente fai lo stesso per gli aggiornamenti. Basta recuperare i dati, modificare il grafico aggiungendo e rimuovendo oggetti dalle collezioni, chiamare SaveChanges. Controlla questa domanda simile per i dettagli.

Modifica :

Secondo il tuo commento, devi inserirne uno nuovo Classe aggiungerne due esistenti 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();
}

Poiché entrambi gli studenti sono già nel database, non verranno inseriti, ma poiché sono ora nella Studentsraccolta di Class, verranno inserite due voci nella StudentClasstabella.


Ciao, grazie per la tua risposta Il mio scenario è che devo inserire 1 voce nella classe e come x il tuo esempio 2 voci nella StudentClass e nessuna voce in Student. Sono confuso come lo faccio
user9969

Ha funzionato a meraviglia. Riguardo all'aggiornamento, c'è qualcosa di speciale che devo fare?
user9969

3
Ciò aggiungerà un sovraccarico per il recupero dal database degli elementi che è necessario aggiungere. Il metodo Attach può essere utilizzato per aggiungere solo una relazione. Vedi msdn.microsoft.com/en-us/data/jj592676.aspx e anche stackoverflow.com/questions/11355019/…
Gnomo

3
AddToClasses è il DbSet per Class?
Jo Smo

1
Non dimenticare di inizializzare le tue raccolte nei costruttori per Class e Student. Ad esempio: public Class () {this.Students = new HashSet <Student> (); }
user1040323

40

Prova questo per l'aggiornamento:

[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);
}

questo mi ha salvato la giornata grazie !!! la loro parte fondamentale è item.Collection (i => i.Students) .Load (); parte
Gerrie Pretorius

Solo una nota a margine, ho avuto un'eccezione InvalidOperationException mentre lo facevo, qualcosa come la mia entità non esisteva nel contesto. Ho appena chiamato context.MyEntityCollection.Attach (myEntity) per gestirlo.
Kilazur

Non l'avrei mai capito. Grazie mille.
Jared Beach,

1
Consentitemi di aggiungere qui i miei ringraziamenti. Ho scritto e testato oltre 130 righe di codice negli ultimi 4 giorni cercando di eseguire questa operazione ma non sono riuscito a farlo. Ho provato questo e le cose hanno funzionato perfettamente. Anche se non capisco lo scopo di stabilire la variabile item e quindi di non usarla affatto, sono solo contento che funzioni! Grazie un milione di bajillion !!!! :)
Dude-Dastic

Considerando che la domanda è Inserisci E Aggiorna, questa risposta completa la domanda e la risposta accettata. Grazie mille!
Vahx

5

Volevo aggiungere la mia esperienza a questo. Infatti EF, quando aggiungi un oggetto al contesto, cambia lo stato di tutti i figli e delle entità correlate in Aggiunto. Sebbene vi sia una piccola eccezione nella regola qui: se le entità secondarie / correlate vengono tracciate dallo stesso contesto, EF capisce che queste entità esistono e non le aggiunge. Il problema si verifica quando, ad esempio, si caricano le entità figlio / correlate da un altro contesto o un'interfaccia utente Web ecc.E poi sì, EF non sa nulla di queste entità e va e le aggiunge tutte. Per evitare ciò, prendi le chiavi delle entità e trovale (es. context.Students.FirstOrDefault(s => s.Name == "Alice"))Nello stesso contesto in cui vuoi fare l'aggiunta.


3

Uso il modo seguente per gestire la relazione molti-a-molti in cui sono coinvolte solo chiavi esterne.

Quindi per l' inserimento :

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();
    }
}

Per l' eliminazione ,

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();
        }
    }
}

1

In entity framework, quando l'oggetto viene aggiunto al contesto, il suo stato cambia in Added. EF cambia anche lo stato di ogni oggetto in aggiunto nella struttura ad albero e quindi stai ricevendo un errore di violazione della chiave primaria o vengono aggiunti record duplicati nella tabella.


2
Si prega di modificare per dare abbastanza dettagli in modo che un utente non ha bisogno di visitare il tuo blog per ottenere la risposta.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.