Bagikan melalui


Penghapusan Kaskade

Entity Framework Core (EF Core) mewakili hubungan menggunakan kunci asing. Entitas dengan kunci asing adalah entitas anak atau dependen dalam hubungan. Nilai kunci asing entitas ini harus cocok dengan nilai kunci utama (atau nilai kunci alternatif) dari entitas utama/induk terkait.

Jika entitas utama/induk dihapus, nilai kunci asing dari entitas bergantung/anak tidak akan lagi sesuai dengan kunci utama atau kunci alternatif dari entitas utama/induk mana pun. Ini adalah status yang tidak valid, dan akan menyebabkan pelanggaran batasan referensial di sebagian besar database.

Ada dua opsi untuk menghindari pelanggaran batasan referensial ini:

  1. Atur nilai FK ke null
  2. Hapus juga entitas dependen/anak

Opsi pertama hanya valid untuk hubungan opsional di mana properti kunci asing (dan kolom basis data yang dipetakan) harus dapat bernilai null.

Opsi kedua dapat diterapkan pada semua jenis hubungan dan dikenal sebagai "penghapusan kaskade".

Petunjuk / Saran

Dokumen ini menjelaskan penghapusan bertingkat (dan menghapus yatim piatu) dari perspektif pembaruan database. Ini memanfaatkan secara berat konsep yang diperkenalkan dalam Pelacakan Perubahan dalam EF Core dan Perubahan Kunci Asing dan Navigasi. Pastikan untuk sepenuhnya memahami konsep-konsep ini sebelum menangani materi di sini.

Petunjuk / Saran

Anda dapat menjalankan dan men-debug ke semua kode dalam dokumen ini dengan mengunduh kode sampel dari GitHub.

Saat perilaku berantai terjadi

Penghapusan berjenjang diperlukan ketika entitas dependen atau anak tidak dapat lagi dikaitkan dengan entitas utama atau induknya saat ini. Ini dapat terjadi karena prinsipal/induk dihapus, atau dapat terjadi ketika prinsipal/induk masih ada tetapi dependen/anak tidak lagi terkait dengannya.

Menghapus prinsipal atau induk

Pertimbangkan model sederhana ini di mana Blog adalah prinsipal/induk dalam hubungan dengan Post, yang merupakan dependen/anak. Post.BlogId adalah properti kunci asing, nilai yang harus cocok dengan Blog.Id kunci utama blog tempat posting berada.

public class Blog
{
    public int Id { get; set; }

    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>();
}

public class Post
{
    public int Id { get; set; }

    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

Menurut konvensi, hubungan ini dikonfigurasi sebagai diperlukan, karena Post.BlogId properti kunci asing tidak dapat diubah ke null. Hubungan yang diperlukan dikonfigurasi untuk menggunakan penghapusan kaskade secara default. Lihat Hubungan untuk informasi selengkapnya tentang hubungan pemodelan.

Saat menghapus blog, semua postingan dihapus secara bertingkat. Contohnya:

using var context = new BlogsContext();

var blog = await context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).FirstAsync();

context.Remove(blog);

await context.SaveChangesAsync();

SaveChanges menghasilkan SQL berikut, menggunakan SQL Server sebagai contoh:

-- Executed DbCommand (1ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p0='2'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (2ms) [Parameters=[@p1='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

Memisahkan hubungan

Daripada menghapus blog, kita justru dapat mengalihkan hubungan antara setiap posting dan blognya. Ini dapat dilakukan dengan mengatur navigasi Post.Blog referensi ke null untuk setiap posting:

using var context = new BlogsContext();

var blog = await context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).FirstAsync();

foreach (var post in blog.Posts)
{
    post.Blog = null;
}

await context.SaveChangesAsync();

Hubungan juga dapat diputus dengan menghapus setiap postingan dari Blog.Posts navigasi koleksi:

using var context = new BlogsContext();

var blog = await context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).FirstAsync();

blog.Posts.Clear();

await context.SaveChangesAsync();

Dalam kedua kasus, hasilnya sama: blog tidak dihapus, tetapi posting yang tidak lagi terkait dengan blog apa pun dihapus:

-- Executed DbCommand (1ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p0='2'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

Menghapus elemen yang tidak lagi terhubung dengan elemen utama atau pendukung dikenal sebagai "menghapus elemen yatim piatu".

Petunjuk / Saran

Penghapusan kaskade dan penghapusan yatim piatu terkait erat. Keduanya mengakibatkan penghapusan entitas turunan atau anak ketika hubungan dengan entitas utama atau induk yang dibutuhkan terputus. Untuk penghapusan berjenjang, pemisahan ini terjadi karena pengelola/induk itu sendiri dihapus. Untuk yatim piatu, entitas utama/induk masih ada, tetapi tidak lagi terkait dengan entitas dependen/anak.

Di mana perilaku berantai terjadi

Perilaku bertingkat dapat diterapkan ke:

  • Entitas yang saat ini dilacak oleh DbContext
  • Entitas dalam database yang belum dimuat ke dalam konteks

Penghapusan berurutan entitas yang dilacak

EF Core selalu menerapkan perilaku bertingkat yang dikonfigurasi ke entitas yang dilacak. Ini berarti bahwa jika aplikasi memuat semua entitas dependen/anak yang relevan ke dalam DbContext, seperti yang ditunjukkan pada contoh di atas, maka perilaku berjenjang akan diterapkan dengan benar terlepas dari bagaimana database dikonfigurasi.

Petunjuk / Saran

Waktu yang tepat ketika perilaku bertingkat terjadi pada entitas yang dilacak dapat dikontrol menggunakan ChangeTracker.CascadeDeleteTiming dan ChangeTracker.DeleteOrphansTiming. Lihat Mengubah Kunci Asing dan Navigasi untuk informasi selengkapnya.

Penghapusan beruntun dalam database

Banyak sistem database juga menawarkan perilaku berskala yang dipicu ketika entitas dihapus dalam database. EF Core mengonfigurasi perilaku ini berdasarkan perilaku penghapusan kaskade dalam model EF Core saat database dibuat menggunakan EnsureCreated atau migrasi EF Core. Misalnya, menggunakan model di atas, tabel berikut dibuat untuk postingan saat menggunakan SQL Server:

CREATE TABLE [Posts] (
    [Id] int NOT NULL IDENTITY,
    [Title] nvarchar(max) NULL,
    [Content] nvarchar(max) NULL,
    [BlogId] int NOT NULL,
    CONSTRAINT [PK_Posts] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blogs] ([Id]) ON DELETE CASCADE
);

Perhatikan bahwa batasan kunci asing yang menentukan hubungan antara blog dan posting dikonfigurasi dengan ON DELETE CASCADE.

Jika kita tahu bahwa database dikonfigurasi seperti ini, maka kita dapat menghapus blog tanpa terlebih dahulu memuat posting dan database akan mengurus penghapusan semua posting yang terkait dengan blog tersebut. Contohnya:

using var context = new BlogsContext();

var blog = await context.Blogs.OrderBy(e => e.Name).FirstAsync();

context.Remove(blog);

await context.SaveChangesAsync();

Perhatikan bahwa Include tidak ada untuk posting, dan karena itu, posting tidak dimuat. SaveChanges dalam hal ini hanya akan menghapus blog, karena itulah satu-satunya entitas yang dilacak:

-- Executed DbCommand (6ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

Ini akan mengakibatkan pengecualian jika batasan kunci asing dalam database tidak dikonfigurasi untuk penghapusan kaskade. Namun, dalam hal ini posting dihapus oleh database karena telah dikonfigurasi dengan ON DELETE CASCADE saat dibuat.

Nota

Database biasanya tidak memiliki cara untuk menghapus yatim piatu secara otomatis. Ini karena sementara EF Core mewakili hubungan menggunakan navigasi serta kunci asing, database hanya memiliki kunci asing dan tidak ada navigasi. Ini berarti bahwa biasanya tidak mungkin untuk memutuskan hubungan tanpa memuat kedua sisi ke dalam DbContext.

Nota

Database in-memory EF Core saat ini tidak mendukung penghapusan kaskade di dalam basis data.

Peringatan

Jangan mengonfigurasi penghapusan berantai di dalam database saat menghapus entitas secara lembut. Ini dapat menyebabkan entitas secara tidak sengaja dihapus permanen alih-alih dihapus lembut.

Batasan database cascade

Beberapa database, terutama SQL Server, memiliki batasan pada perilaku bertingkat yang membentuk siklus. Misalnya, pertimbangkan model berikut:

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>();

    public int OwnerId { get; set; }
    public Person Owner { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }

    public int AuthorId { get; set; }
    public Person Author { get; set; }
}

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>();

    public Blog OwnedBlog { get; set; }
}

Model ini memiliki tiga hubungan, semuanya diperlukan dan oleh karena itu dikonfigurasi untuk menghapus bertahap menurut konvensi:

  • Menghapus blog akan menghapus semua posting terkait
  • Menghapus penulis postingan akan menyebabkan postingan yang ditulis dihapus secara bertingkat
  • Menghapus pemilik blog akan menyebabkan blog dihapus secara kaskade

Semua ini masuk akal (meskipun kebijakan manajemen blog cukup ketat!) tetapi ketika mencoba untuk membuat database SQL Server dengan kaskade yang dikonfigurasi ini, akan menghasilkan pengecualian berikut:

Microsoft.Data.SqlClient.SqlException (0x80131904): Memperkenalkan batasan KUNCI ASING 'FK_Posts_Person_AuthorId' pada tabel 'Posts' dapat menyebabkan siklus atau beberapa jalur kaskade. Tentukan ON DELETE NO ACTION atau ON UPDATE NO ACTION, atau ubah batasan KUNCI ASING lainnya.

Ada dua cara untuk menangani situasi ini:

  1. Ubah satu atau beberapa hubungan agar tidak melakukan penghapusan berurutan.
  2. Konfigurasikan database tanpa satu atau beberapa penghapusan bertingkat ini, lalu pastikan semua entitas dependen dimuat sehingga EF Core dapat melakukan perilaku bertingkat.

Menggunakan pendekatan pertama dengan contoh kami, kita dapat menjadikan hubungan pasca-blog bersifat opsional dengan memberinya properti kunci asing yang dapat bernilai null.

public int? BlogId { get; set; }

Hubungan opsional memungkinkan postingan ada tanpa blog, yang berarti penghapusan bertingkat tidak akan lagi dikonfigurasi secara default. Ini berarti tidak ada lagi siklus dalam tindakan berkala, dan database dapat dibuat tanpa kesalahan di SQL Server.

Dengan mengambil pendekatan kedua, kita dapat menjaga hubungan pemilik blog yang diperlukan dan dikonfigurasi untuk penghapusan bertingkat, tetapi membuat konfigurasi ini hanya berlaku untuk entitas yang dilacak, bukan database:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Blog>()
        .HasOne(e => e.Owner)
        .WithOne(e => e.OwnedBlog)
        .OnDelete(DeleteBehavior.ClientCascade);
}

Sekarang apa yang terjadi jika kita memuat seseorang dan blog yang mereka miliki, lalu menghapus orang tersebut?

using var context = new BlogsContext();

var owner = await context.People.SingleAsync(e => e.Name == "ajcvickers");
var blog = await context.Blogs.SingleAsync(e => e.Owner == owner);

context.Remove(owner);

await context.SaveChangesAsync();

EF Core akan menghapus secara berjenjang pada pemilik sehingga blog juga dihapus.

-- Executed DbCommand (8ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (2ms) [Parameters=[@p1='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [People]
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

Namun, jika blog tidak dimuat ketika pemilik dihapus:

using var context = new BlogsContext();

var owner = await context.People.SingleAsync(e => e.Name == "ajcvickers");

context.Remove(owner);

await context.SaveChangesAsync();

Kemudian pengecualian akan dilemparkan karena pelanggaran batasan kunci asing dalam database:

Microsoft.Data.SqlClient.SqlException: Pernyataan DELETE bertentangan dengan batasan REFERENSI "FK_Blogs_People_OwnerId". Konflik terjadi dalam database "Scratch", tabel "dbo. Blogs", kolom 'OwnerId'. Pernyataan ini telah dihapus.

Nilai null berurutan

Hubungan opsional memiliki properti kunci asing null yang dipetakan ke kolom database nullable. Ini berarti bahwa nilai kunci asing dapat diatur ke null ketika entitas utama/induk saat ini dihapus atau hubungan dengan dependen/anak diputus.

Mari kita lihat lagi contoh dari Ketika perilaku berjenjang terjadi, tetapi kali ini dengan hubungan opsional yang diwakili oleh properti kunci asing yang bersifat null:

public int? BlogId { get; set; }

Properti kunci asing ini akan diatur ke null untuk setiap postingan ketika blog terkait dihapus. Misalnya, kode ini, yang sama seperti sebelumnya:

using var context = new BlogsContext();

var blog = await context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).FirstAsync();

context.Remove(blog);

await context.SaveChangesAsync();

Sekarang akan menghasilkan pembaruan database berikut ketika SaveChanges dipanggil:

-- Executed DbCommand (2ms) [Parameters=[@p1='1', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p1='2', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

-- Executed DbCommand (1ms) [Parameters=[@p2='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p2;
SELECT @@ROWCOUNT;

Demikian juga, jika hubungan terputus menggunakan salah satu contoh dari atas:

using var context = new BlogsContext();

var blog = await context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).FirstAsync();

foreach (var post in blog.Posts)
{
    post.Blog = null;
}

await context.SaveChangesAsync();

Atau:

using var context = new BlogsContext();

var blog = await context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).FirstAsync();

blog.Posts.Clear();

await context.SaveChangesAsync();

Kemudian postingan diperbarui dengan nilai kunci asing null saat SaveChanges dipanggil:

-- Executed DbCommand (2ms) [Parameters=[@p1='1', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p1='2', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

Lihat Mengubah Kunci Asing dan Navigasi untuk informasi selengkapnya tentang cara EF Core mengelola kunci asing dan navigasi saat nilainya diubah.

Nota

Perbaikan hubungan seperti ini telah menjadi perilaku default Kerangka Kerja Entitas sejak versi pertama pada 2008. Sebelum EF Core tidak memiliki nama dan tidak mungkin diubah. Sekarang dikenal sebagai ClientSetNull seperti dijelaskan di bagian berikutnya.

Basis data juga dapat dikonfigurasi untuk menghapus nilai null seperti ini ketika prinsipal/induk dalam hubungan opsional dihapus. Namun, ini jauh kurang umum daripada menggunakan penghapusan berskala dalam database. Menggunakan penghapusan berjenjang dan null berjenjang dalam database secara bersamaan hampir selalu mengakibatkan siklus relasi saat menggunakan SQL Server. Lihat bagian berikutnya untuk informasi selengkapnya tentang mengonfigurasi null bertingkat.

Mengonfigurasi perilaku bertingkat

Petunjuk / Saran

Pastikan untuk membaca bagian di atas sebelum datang ke sini. Opsi konfigurasi kemungkinan tidak akan masuk akal jika materi sebelumnya tidak dipahami.

Perilaku kaskade dikonfigurasi per hubungan menggunakan metode OnDelete di OnModelCreating. Contohnya:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Blog>()
        .HasOne(e => e.Owner)
        .WithOne(e => e.OwnedBlog)
        .OnDelete(DeleteBehavior.ClientCascade);
}

Lihat Hubungan untuk informasi selengkapnya tentang mengonfigurasi hubungan antar jenis entitas.

OnDelete menerima nilai dari enum DeleteBehavior yang diakui membingungkan. Enum ini mendefinisikan perilaku EF Core pada entitas yang dilacak, dan konfigurasi penghapusan bertingkat dalam database ketika EF digunakan untuk membuat skema.

Dampak pada skema database

Tabel berikut menunjukkan hasil dari setiap nilai OnDelete pada batasan kunci asing yang dibuat oleh migrasi EF Core atau EnsureCreated.

DeleteBehavior Dampak pada skema database
Air terjun ON DELETE CASCADE (Hapus dengan Caleburan)
Membatasi PADA HAPUS BATASAN
TidakAdaTindakan default database
SetNull Saat Dihapus Tetapkan ke NULL
ClientSetNull default database
ClientCascade default database
ClientNoAction default database

Perilaku ON DELETE NO ACTION (default database) dan ON DELETE RESTRICT dalam database relasional biasanya identik atau sangat mirip. Terlepas dari apa yang NO ACTION mungkin menyiratkan, kedua opsi ini menyebabkan kendala referensial diberlakukan. Perbedaannya, ketika ada, adalah ketika database memeriksa batasan. Periksa dokumentasi database Anda untuk mengetahui perbedaan spesifik antara ON DELETE NO ACTION dan ON DELETE RESTRICT pada sistem database Anda.

SQL Server tidak mendukung ON DELETE RESTRICT, jadi ON DELETE NO ACTION digunakan sebagai gantinya.

Satu-satunya nilai yang akan menyebabkan perilaku berskala pada database adalah Cascade dan SetNull. Semua nilai lain akan mengonfigurasi database untuk tidak meneruskan perubahan apa pun.

Dampak pada perilaku SaveChanges

Tabel di bagian berikut mencakup apa yang terjadi pada entitas dependen/anak ketika prinsipal/induk dihapus, atau hubungannya dengan entitas dependen/anak terputus. Setiap tabel mencakup salah satu dari:

  • Hubungan opsional (FK dapat bernilai null) dan wajib (FK tidak dapat bernilai null)
  • Ketika anggota keluarga yang menjadi tanggungan/anak-anak diinisialisasi dan dipantau oleh DbContext dan ketika mereka hanya ada di database

Hubungan yang diperlukan dengan dependen/anak dimuat

DeleteBehavior Saat menghapus entitas utama/induk Saat memisahkan dari induk/prinsipal
Air terjun Ketergantungan yang dihapus oleh EF Core Ketergantungan yang dihapus oleh EF Core
Membatasi InvalidOperationException InvalidOperationException
TidakAdaTindakan InvalidOperationException InvalidOperationException
SetNull SqlException dalam pembuatan database SqlException dalam pembuatan database
ClientSetNull InvalidOperationException InvalidOperationException
ClientCascade Ketergantungan yang dihapus oleh EF Core Ketergantungan yang dihapus oleh EF Core
ClientNoAction DbUpdateException InvalidOperationException

Catatan:

  • Pengaturan baku untuk hubungan yang diperlukan seperti ini adalah Cascade.
  • Menggunakan apa pun selain penghapusan kaskade untuk hubungan yang diperlukan akan menghasilkan pengecualian saat SaveChanges dipanggil.
    • Biasanya, ini adalah InvalidOperationException dari EF Core karena status tidak valid terdeteksi dalam anak-anak/dependen yang dimuat.
    • ClientNoAction memaksa EF Core untuk tidak memeriksa dependen perbaikan sebelum mengirimkannya ke database, jadi dalam hal ini database melemparkan pengecualian, yang kemudian dibungkus dalam DbUpdateException oleh SaveChanges.
    • SetNull ditolak saat membuat database karena kolom kunci asing tidak dapat diubah ke null.
  • Karena dependent/anak telah dimuat, dependent/anak selalu dihapus oleh EF Core, dan tidak pernah dibiarkan untuk dihapus oleh database.

Hubungan yang diperlukan dengan tanggungan/anak tidak dimuat

DeleteBehavior Saat menghapus entitas utama/induk Saat memisahkan dari induk/prinsipal
Air terjun Entri yang bergantung dihapus oleh basis data Tidak tersedia
Membatasi DbUpdateException Tidak tersedia
TidakAdaTindakan DbUpdateException Tidak tersedia
SetNull SqlException dalam pembuatan database Tidak tersedia
ClientSetNull DbUpdateException Tidak tersedia
ClientCascade DbUpdateException Tidak tersedia
ClientNoAction DbUpdateException Tidak tersedia

Catatan:

  • Memutuskan hubungan tidak berlaku di sini karena tanggungan/anak tidak dimuat.
  • Pengaturan baku untuk hubungan yang diperlukan seperti ini adalah Cascade.
  • Menggunakan apa pun selain penghapusan kaskade untuk hubungan yang diperlukan akan menghasilkan pengecualian saat SaveChanges dipanggil.
    • Biasanya, ini karena DbUpdateException dependen/anak tidak dimuat, dan karenanya status tidak valid hanya dapat dideteksi oleh database. SaveChanges kemudian membungkus pengecualian database dalam DbUpdateException.
    • SetNull ditolak saat membuat database karena kolom kunci asing tidak dapat diubah ke null.

Hubungan opsional dengan dependen/anak dimuat

PerilakuHapus Saat menghapus entitas utama/induk Saat memisahkan dari induk/prinsipal
Air terjun Ketergantungan yang dihapus oleh EF Core Ketergantungan yang dihapus oleh EF Core
Membatasi FK Dependen diatur ke null oleh EF Core FK Dependen diatur ke null oleh EF Core
TidakAdaTindakan FK Dependen diatur ke null oleh EF Core FK Dependen diatur ke null oleh EF Core
SetNull FK Dependen diatur ke null oleh EF Core FK Dependen diatur ke null oleh EF Core
ClientSetNull FK Dependen diatur ke null oleh EF Core FK Dependen diatur ke null oleh EF Core
ClientCascade Ketergantungan yang dihapus oleh EF Core Ketergantungan yang dihapus oleh EF Core
ClientNoAction DbUpdateException FK Dependen diatur ke null oleh EF Core

Catatan:

  • Default untuk hubungan opsional seperti ini adalah ClientSetNull.
  • Dependen/anak tidak pernah dihapus kecuali Cascade atau ClientCascade dikonfigurasi.
  • Semua nilai lainnya menyebabkan FK dependen diatur ke null (tidak ada nilai) oleh EF Core...
    • ... kecuali ClientNoAction yang memberi tahu EF Core untuk tidak menyentuh kunci asing dependen/anak ketika prinsipal/induk dihapus. Oleh karena itu, database menghasilkan pengecualian, yang dibungkus sebagai DbUpdateException oleh SaveChanges.

Hubungan opsional dengan tanggungan/anak tidak terisi

DeleteBehavior Saat menghapus entitas utama/induk Saat memisahkan dari induk/prinsipal
Air terjun Entri yang bergantung dihapus oleh basis data Tidak tersedia
Membatasi DbUpdateException Tidak tersedia
TidakAdaTindakan DbUpdateException Tidak tersedia
SetNull FK Dependen diatur ke null menurut database Tidak tersedia
ClientSetNull DbUpdateException Tidak tersedia
ClientCascade DbUpdateException Tidak tersedia
ClientNoAction DbUpdateException Tidak tersedia

Catatan:

  • Memutuskan hubungan tidak berlaku di sini karena tanggungan/anak tidak dimuat.
  • Default untuk hubungan opsional seperti ini adalah ClientSetNull.
  • Tanggungan/anak perlu dimuat untuk menghindari pengecualian database, kecuali jika database telah dikonfigurasi untuk menerapkan penghapusan atau menjadikan nol.