さて、私は1対多の関連モデルを持っています:
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public string ChildName { get; set; }
}
私がしたいことは明確ですParent.Children
および関連する子エンティティをデータベースから削除します。私はすでに試しました:
データベースコンテキストクラス:
modelBuilder.Entity<Parent>()
.HasMany(p => p.Children)
.WithOptional()
.WillCascadeOnDelete(true);
これは問題なく動作しますが、Parent_Id = null
私がするときのフィールド
parent.Children.Clear();
repository.InsertOrUpdate(parent);
私のリポジトリクラスで。また、同じ動作は私が行うときです:
modelBuilder.Entity<Parent>()
.HasMany(pr => pr.Children)
.WithOptional(ri => ri.Parent)
.WillCascadeOnDelete(true);
Parent
クラスにChild
プロパティが追加されています
public class Child
{
...
public Parent Parent { get; set; }
...
}
または私がするとき
modelBuilder.Entity<Child>()
.HasOptional(p => p.Parent)
.WithMany(p => p.Children)
.HasForeignKey(p => p.Parent_Id)
.WillCascadeOnDelete(true);
Child
クラスに追加のParent_Idプロパティがある
public class Child
{
...
public int Parent_Id { get; set; }
...
}
つまり、カスケード削除を正しく構成するにはどうすればよいですか?またはそれらの子エンティティを削除するにはどうすればよいですか?これはカジュアルなタスクだと思いますが、何かが不足しています
カスケード削除は、parent
を削除するのではなく、InsertOrUpdate
を呼び出すだけなので、ここでは効果がありません。正しい手順は、たとえば次のように、子を1つずつ削除することです。
using (var context = new MyContext())
{
var parent = context.Parents.Include(p => p.Children)
.SingleOrDefault(p => p.Id == parentId);
foreach (var child in parent.Children.ToList())
context.Children.Remove(child);
context.SaveChanges();
}
EF6で操作を行うより速い方法は...
context.Children.RemoveRange(parent.Children)
これは「孤児の削除」と呼ばれます。
親が削除されていない孤立したデータをEFは自動的に削除できますか?
EF6でどのように機能するのかわかりませんが、EF Coreではうまく機能します https://docs.Microsoft.com/en-us/ef/core/saving/cascade-delete カスケードが機能するために必ずしも親を削除する必要はありません。
に変更してみてください
public virtual ICollection<Child> Children { get; set; }
遅延読み込みには仮想が必要だからです。説明通り こちら
子がロードされていないため、parent.Children.clearは機能していません
オブジェクトが自己参照している場合は、以下の方法を使用して、多対多および1対多の両方の子を削除できます。後でdb.SaveChanges()を呼び出すことを忘れないでください:)
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Object obj = this.db.Objects.Find(id);
this.DeleteObjectAndChildren(obj);
this.db.Objects.Remove(obj);
this.db.SaveChanges();
return this.Json(new { success = true });
}
/// <summary>
/// This deletes an object and all children, but does not commit changes to the db.
/// - MH @ 2016/08/15 14:42
/// </summary>
/// <param name="parent">
/// The object.
/// </param>
private void DeleteObjectAndChildren(Object parent)
{
// Deletes One-to-Many Children
if (parent.Things != null && parent.Things.Count > 0)
{
this.db.Things.RemoveRange(parent.Things);
}
// Deletes Self Referenced Children
if (parent.Children != null && parent.Children.Count > 0)
{
foreach (var child in parent.Children)
{
this.DeleteObjectAndChildren(child);
}
this.db.Objects.RemoveRange(parent.Children);
}
}