web-dev-qa-db-ja.com

多対多エンティティフレームワークの挿入/更新。どうすればいいのですか?

私はEF4を使用していますが、新しいものです。私のプロジェクトには多対多があり、挿入または更新の方法がうまくいかないようです。私はそれがどのようにコーディングされるべきかを見るためだけに小さなプロジェクトを構築しました。

3つのテーブルがあるとします

  1. クラス:ClassID-ClassName
  2. 学生:StudentID-FirstName-Surname
  3. StudentClass:StudentID-ClassID

すべての関係を追加し、モデルブラウザでモデルを更新した後、StudentClassが表示されないことに気付きました。これはデフォルトの動作のようです。

次に、挿入と更新の両方を行う必要があります。どうやってやるの?サンプルをダウンロードできるコードサンプルまたはリンク、または5分間の余裕はありますか?

101
user9969

エンティティ(またはオブジェクト)に関しては、Classのコレクションを持つStudentsオブジェクトと、Studentのコレクションを持つClassesオブジェクトがあります。 StudentClassテーブルにはIDのみが含まれ、追加情報は含まれていないため、EFは結合テーブルのエンティティを生成しません。それが正しい動作であり、それはあなたが期待することです。

さて、挿入または更新を行うときは、オブジェクトの観点から考えてみてください。例えば。クラスを2人の生徒で挿入する場合は、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テーブルに2つのエントリ、StudentClassテーブルに2つのエントリがリンクされます。

基本的に更新についても同様です。データを取得し、コレクションにオブジェクトを追加および削除してグラフを変更し、SaveChangesを呼び出します。詳細については、 この同様の質問 を確認してください。

編集

コメントによると、新しいClassを挿入し、2つの既存の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();
}

両方の生徒がすでにデータベースにあるため、挿入されませんが、現在StudentsClassコレクションにあるため、2つのエントリがStudentClassテーブルに挿入されます。

135
Yakimych

更新のためにこれを試してください:

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

その上で私の経験を加えたかった。実際、EFは、オブジェクトをコンテキストに追加すると、すべての子および関連エンティティの状態を「追加済み」に変更します。ここでのルールには小さな例外があります:子/関連エンティティが同じコンテキストで追跡されている場合、EFはこれらのエンティティが存在することを理解し、それらを追加しません。この問題は、たとえば、他のコンテキストまたはWeb UIなどから子/関連エンティティをロードしたときに発生します。そうすると、EFはこれらのエンティティについて何も認識せず、それらすべてを追加します。これを回避するには、エンティティのキ​​ーを取得して検索します(たとえば、追加を行うコンテキストと同じコンテキストでcontext.Students.FirstOrDefault(s => s.Name == "Alice")).

4
Athina

次の方法を使用して、外部キーのみが関係する多対多の関係を処理します。

挿入の場合:

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

エンティティフレームワークでは、オブジェクトがコンテキストに追加されると、その状態が[追加済み]に変わります。また、EFは各オブジェクトの状態をオブジェクトツリーに追加するため、主キー違反エラーが発生するか、テーブルに重複レコードが追加されます。

1
Nilesh Hirapra