Entity Framework 6:コードファーストカスケード削除

c# entity-framework entity-framework-6 sql

質問

ここにはこれに似た疑問がいくつかありますが、単純化されたシナリオでは正確に何が欠けているのかを判断する問題があります。

自分の名前を巧みに使って次のテーブルを持っているとしましょう:

'JohnsParentTable' (Id, Description) 
'JohnsChildTable' (Id, JohnsParentTableId, Description)

結果として得られるクラスはそうであるように見える

public class JohnsParentTable
{
    public int Id { get; set; }
    public string Description { get; set; }
    public virtual ICollection<JohnsChildTable> JohnsChildTable { get; set; }

    public JohnsParentTable()
    {
        JohnsChildTable = new List<JohnsChildTable>();
    }
}

internal class JohnsParentTableConfiguration : EntityTypeConfiguration<JohnsParentTable>
{
    public JohnsParentTableConfiguration()
    {
        ToTable("dbo.JohnsParentTable");
        HasKey(x => x.Id);
        Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.Description).HasColumnName("Description").IsRequired().HasMaxLength(50);
    }
}

public class JohnsChildTable
{
    public int Id { get; set; }
    public string Description { get; set; }
    public int JohnsParentTableId { get; set; }
    public JohnsParentTable JohnsParentTable { get; set; }
}

internal class JohnsChildTableConfiguration : EntityTypeConfiguration<JohnsChildTable>
{
    public JohnsChildTableConfiguration()
    {
        ToTable("dbo.JohnsChildTable");
        HasKey(x => x.Id);
        Property(x => x.Id).HasColumnName("Id").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.Description).HasColumnName("Description").IsRequired().HasMaxLength(50);
        HasRequired(a => a.JohnsParentTable).WithMany(c => c.JohnsChildTable).HasForeignKey(a => a.JohnsParentTableId);
    }
}

データベースでは、私はこの親に関連付けられている子テーブルの2つの行と一緒に1のIDを持つ親テーブルの行を持っています。私がこれを行うならば:

var parent = db.JohnsParentTable.FirstOrDefault(a => a.Id == 1)

オブジェクトには正しく入力されています。ただし、この行を削除しようとすると:

var parent = new Data.Models.JohnsParentTable() { Id = 1 };
db.JohnsParentTable.Attach(parent);
db.JohnsParentTable.Remove(parent);

db.SaveChanges();

Entityフレームワークは、次の処理を実行しようとします。

DELETE [dbo].[JohnsParentTable]
WHERE ([Id] = @0)
-- @0: '1' (Type = Int32)
-- Executing at 1/23/2014 10:34:01 AM -06:00
-- Failed in 103 ms with error: The DELETE statement conflicted with the REFERENCE constraint "FK_JohnsChildTable_JohnsParentTable". The conflict occurred in database "mydatabase", table "dbo.JohnsChildTable", column 'JohnsParentTableId'.
The statement has been terminated.

私の質問は、Entity Frameworkが親を削除する前に 'JohnsChildTable'行を削除しなければならないことを確実にするために、何が欠けているのでしょうか?

受け入れられた回答

Entity Frameworkで子を削除するか、データベースで処理するかによって異なります。

EFにすべての子に対してdelete文を生成させ、親を削除する前にそれらを実行させたい場合は、最初にすべての子をメモリにロードする必要があります。

だから、あなたは単純にキーが設定された "ダミー"エンティティを作成することはできず、子を削除することを期待することはできません。

それが機能するには、データベースが削除を処理するようにする必要があります。

ただし、子テーブルの外部キーにはカスケード削除が有効になっている必要があります。その場合、Entity Frameworkは親のdeleteステートメントを作成し、データベースは子も削除することを知っています。

エンティティフレームワークは、カスケード削除がデフォルトで有効になっている外部キーを作成します。 (外部キーはnullにできません)。

自分でデータベースを作成した場合は、データベースを有効にすることを忘れないでください。


人気のある回答

OnModelCreatingメソッドをオーバーライドしてこのコードを追加する方が良いと思います。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
   modelBuilder.Entity<JohnsChildTable>()
               .HasRequired(t=>t.JohnsParentTable)
               .WithMany(t=>t.JohnsChildTables)
               .HasForeignKey(d=>d.JohnsParentTableId)
               .WillCascadeOnDelete(true);

            base.OnModelCreating(modelBuilder);
}

私はtrueに設定しましたWillCascadeOnDelete(true)



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ