แทรก / อัปเดตหลาย ๆ เอนทิตีกรอบงาน ฉันต้องทำอย่างไร?


105

ฉันใช้ EF4 และเป็นมือใหม่ ฉันมีโปรเจ็กต์หลายรายการและหลายรายการและดูเหมือนจะหาวิธีแทรกหรืออัปเดตไม่ได้ ฉันได้สร้างโครงการเล็ก ๆ เพื่อดูว่าควรจะเขียนโค้ดอย่างไร

สมมติว่าฉันมี 3 โต๊ะ

  1. คลาส: ClassID-ClassName
  2. นักเรียน: StudentID-FirstName - นามสกุล
  3. StudentClass: StudentID-ClassID

หลังจากเพิ่มความสัมพันธ์ทั้งหมดและอัปเดตโมเดลผ่านเบราว์เซอร์โมเดลฉันสังเกตเห็นว่า StudentClass ไม่ปรากฏขึ้นดูเหมือนว่าจะเป็นพฤติกรรมเริ่มต้น

ตอนนี้ฉันต้องทำทั้งส่วนแทรกและอัปเดต คุณจะทำอย่างไรมันได้หรือไม่? ตัวอย่างโค้ดหรือลิงค์ใด ๆ ที่ฉันสามารถดาวน์โหลดตัวอย่างได้หรือคุณสามารถเผื่อเวลาไว้ 5 นาทีได้หรือไม่?

คำตอบ:


141

ในแง่ของหน่วยงาน (หรือวัตถุ) คุณมีClassวัตถุที่มีคอลเลกชันของStudentsและวัตถุที่มีคอลเลกชันของStudent Classesเนื่องจากStudentClassตารางของคุณมีเฉพาะรหัสและไม่มีข้อมูลเพิ่มเติม EF จึงไม่สร้างเอนทิตีสำหรับตารางการเข้าร่วม นั่นคือพฤติกรรมที่ถูกต้องและนั่นคือสิ่งที่คุณคาดหวัง

ตอนนี้เมื่อทำการแทรกหรืออัพเดตพยายามคิดในแง่ของวัตถุ เช่นถ้าคุณต้องการแทรกชั้นเรียนที่มีนักเรียนสองคนสร้างClassวัตถุStudentวัตถุเพิ่มนักเรียนในStudentsคอลเล็กชันชั้นเรียนให้เพิ่มClassวัตถุในบริบทและเรียก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();
}

สิ่งนี้จะสร้างรายการในClassตารางสองรายการในStudentตารางและสองรายการในStudentClassตารางที่เชื่อมโยงเข้าด้วยกัน

โดยพื้นฐานแล้วคุณจะทำเช่นเดียวกันสำหรับการอัปเดต SaveChangesเพียงแค่ดึงข้อมูลปรับเปลี่ยนกราฟโดยการเพิ่มและลบวัตถุจากคอลเลกชันโทร ตรวจสอบคำถามที่คล้ายกันนี้เพื่อดูรายละเอียด

แก้ไข :

ตามความคิดเห็นของคุณคุณต้องแทรกใหม่Classและเพิ่มสองรายการที่มีอยู่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();
}

เนื่องจากนักเรียนทั้งสองคนอยู่ในฐานข้อมูลแล้วจึงไม่สามารถแทรกได้ แต่เนื่องจากตอนนี้พวกเขาอยู่ในStudentsคอลเลกชันของClassข้อมูลทั้งสองรายการจะถูกแทรกลงในStudentClassตาราง


สวัสดีขอบคุณสำหรับคำตอบของคุณสถานการณ์ของฉันคือฉันต้องแทรก 1 รายการในชั้นเรียนและในฐานะที่เป็น x ตัวอย่างของคุณ 2 รายการใน StudentClass และไม่มีการเข้าสู่ Student ฉันสับสนว่าฉันทำเช่นนั้นได้อย่างไร
user9969

ที่ทำงานได้รับการรักษาเกี่ยวกับการอัปเดตฉันต้องทำอะไรเป็นพิเศษหรือไม่ EG เพียงแค่อัปเดต className เป็นต้น
user9969

3
สิ่งนี้จะเพิ่มค่าใช้จ่ายในการดึงข้อมูลจากฐานข้อมูลที่จำเป็นต้องเพิ่ม สามารถใช้วิธีการแนบเพื่อเพิ่มเฉพาะความสัมพันธ์ ดูmsdn.microsoft.com/en-us/data/jj592676.aspxและstackoverflow.com/questions/11355019/…
Gnomo

4
AddToClasses คือ DbSet for Class หรือไม่?
Jo Smo

1
อย่าลืมเริ่มต้นคอลเล็กชันของคุณในตัวสร้างสำหรับชั้นเรียนและนักเรียน ตัวอย่างเช่น public Class () {this.Students = new HashSet <Student> (); }
user1040323

41

ลองใช้อันนี้เพื่ออัปเดต:

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

วันนี้ช่วยฉันไว้ขอบคุณ !!! พวกเขาเป็นส่วนสำคัญคือ item.Collection (i => i.Students) .Load (); ส่วน
Gerrie Pretorius

เพียงบันทึกด้านข้างฉันมี InvalidOperationException เมื่อทำเช่นนั้นสิ่งที่คล้ายกับเอนทิตีของฉันไม่มีอยู่ในบริบท ฉันเรียกว่าบริบท MyEntityCollection.Attach (myEntity) เพื่อจัดการกับมัน
Kilazur

จะไม่คิดออก ขอบคุณมาก
Jared Beach

1
ขออนุญาตเพิ่มคำขอบคุณที่นี่ ฉันเขียนและทดสอบโค้ดกว่า 130 บรรทัดในช่วง 4 วันที่ผ่านมาพยายามทำงานนี้ให้สำเร็จ แต่ไม่สามารถทำได้ ลองสิ่งนี้แล้วสิ่งต่างๆก็ทำงานได้อย่างสมบูรณ์ แม้ว่าฉันจะไม่เข้าใจจุดประสงค์ของการสร้างตัวแปรไอเท็ม แต่ก็ไม่ได้ใช้เลย แต่ฉันก็ดีใจที่มันใช้งานได้! ขอบคุณล้านล้าน !!!! :)
Dude-Dastic

เมื่อพิจารณาว่าคำถามคือการแทรกและอัปเดตคำตอบนี้จะทำให้คำถามสมบูรณ์และเป็นคำตอบที่ยอมรับ ขอบคุณมาก!
Vahx

5

ฉันต้องการเพิ่มประสบการณ์ของฉันในเรื่องนั้น EF ที่จริงเมื่อคุณเพิ่มอ็อบเจกต์ลงในบริบทจะเปลี่ยนสถานะของเด็กและเอนทิตีที่เกี่ยวข้องทั้งหมดเป็นเพิ่ม แม้ว่าจะมีข้อยกเว้นเล็กน้อยในกฎที่นี่: หากหน่วยงานย่อย / เอนทิตีที่เกี่ยวข้องถูกติดตามโดยบริบทเดียวกัน EF เข้าใจว่าเอนทิตีเหล่านี้มีอยู่จริงและไม่ได้เพิ่มเข้าไป ปัญหาเกิดขึ้นเมื่อคุณโหลดเอนทิตีลูก / เอนทิตีที่เกี่ยวข้องจากบริบทอื่น ๆ หรือเว็บ ui และอื่น ๆ จากนั้นใช่ EF ไม่รู้อะไรเกี่ยวกับเอนทิตีเหล่านี้และไปและเพิ่มเอนทิตีทั้งหมด เพื่อหลีกเลี่ยงสิ่งนั้นเพียงแค่รับคีย์ของเอนทิตีและค้นหา (เช่นcontext.Students.FirstOrDefault(s => s.Name == "Alice"))ในบริบทเดียวกับที่คุณต้องการทำการเพิ่ม


3

ฉันใช้วิธีต่อไปนี้เพื่อจัดการกับความสัมพันธ์แบบกลุ่มต่อกลุ่มที่มีเฉพาะคีย์ต่างประเทศเท่านั้นที่เกี่ยวข้อง

ดังนั้นสำหรับการแทรก :

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

สำหรับการลบ ,

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

ในกรอบงานเอนทิตีเมื่อเพิ่มวัตถุในบริบทสถานะจะเปลี่ยนเป็นเพิ่ม นอกจากนี้ EF ยังเปลี่ยนสถานะของแต่ละวัตถุเพื่อเพิ่มในโครงสร้างวัตถุและด้วยเหตุนี้คุณจึงได้รับข้อผิดพลาดในการละเมิดคีย์หลักหรือระเบียนที่ซ้ำกันจะถูกเพิ่มในตาราง


2
โปรดแก้ไขเพื่อให้รายละเอียดเพียงพอเพื่อให้ผู้ใช้ไม่ต้องไปที่บล็อกของคุณเพื่อรับคำตอบ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.