Bagikan melalui


Kunci asing dan utama dalam hubungan

Semua hubungan satu-ke-satu dan satu-ke-banyak didefinisikan oleh kunci asing pada ujung dependen yang mereferensikan kunci utama atau alternatif di ujung utama. Untuk kenyamanan, kunci utama atau alternatif ini dikenal sebagai "kunci utama" untuk hubungan tersebut. Hubungan banyak ke banyak terdiri dari dua hubungan satu-ke-banyak, yang masing-masing didefinisikan oleh kunci asing yang merujuk kunci utama.

Petunjuk / Saran

Kode di bawah ini dapat ditemukan di ForeignAndPrincipalKeys.cs.

Kunci asing

Properti atau properti yang membentuk kunci asing sering ditemukan berdasarkan konvensi. Properti juga dapat dikonfigurasi secara eksplisit menggunakan atribut pemetaan atau dengan HasForeignKey di API pembuatan model. HasForeignKey dapat digunakan dengan ekspresi lambda. Misalnya, untuk kunci asing yang terdiri dari satu properti:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.ContainingBlogId);
}

Atau, untuk kunci asing gabungan yang terdiri dari lebih dari satu properti:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => new { e.ContainingBlogId1, e.ContainingBlogId2 });
}

Petunjuk / Saran

Menggunakan ekspresi lambda dalam API pembuatan model memastikan bahwa penggunaan properti tersedia untuk analisis kode dan pemfaktoran ulang, dan juga menyediakan jenis properti ke API untuk digunakan dalam metode berantai lebih lanjut.

HasForeignKey juga dapat diteruskan nama properti kunci asing sebagai string. Misalnya, untuk satu properti:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey("ContainingBlogId");
}

Atau, untuk kunci asing komposit:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey("ContainingBlogId1", "ContainingBlogId2");
}

Menggunakan string berguna saat:

  • Properti bersifat pribadi.
  • Properti-properti tidak ada pada jenis entitas dan harus dibuat sebagai properti bayangan.
  • Nama properti dihitung atau dibangun berdasarkan beberapa input ke proses pembuatan model.

Kolom kunci asing yang tidak dapat diubah ke null

Seperti yang dijelaskan dalam Hubungan bersifat opsional dan diperlukan, ke-null-an dari properti kunci asing menentukan apakah hubungan tersebut bersifat opsional atau diperlukan. Namun, properti kunci asing yang dapat diubah ke null dapat digunakan untuk hubungan yang diperlukan menggunakan [Required] atribut , atau dengan memanggil IsRequired di API pembuatan model. Contohnya:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.BlogId)
        .IsRequired();
}

Atau, jika kunci asing ditemukan berdasarkan konvensi, maka IsRequired dapat digunakan tanpa panggilan ke HasForeignKey:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .IsRequired();
}

Hasil akhirnya dari ini adalah bahwa kolom kunci asing dalam database dibuat tidak bernilai null meskipun properti kunci asing bernilai null. Hal yang sama dapat dicapai dengan secara eksplisit mengonfigurasi properti kunci asing itu sendiri sesuai kebutuhan. Contohnya:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .Property(e => e.BlogId)
        .IsRequired();
}

Kunci asing bayangan

Properti kunci asing dapat dibuat sebagai properti bayangan. Properti bayangan ada dalam model EF tetapi tidak ada pada jenis .NET. EF melacak nilai properti dan status secara internal.

Kunci asing bayangan biasanya digunakan ketika ada keinginan untuk menyembunyikan konsep relasional kunci asing dari model domain yang digunakan oleh kode aplikasi/logika bisnis. Kode aplikasi ini kemudian memanipulasi hubungan sepenuhnya melalui navigasi.

Petunjuk / Saran

Jika entitas akan diserialisasikan, misalnya untuk mengirim melalui kawat, maka nilai kunci asing dapat menjadi cara yang berguna untuk menjaga informasi hubungan tetap utuh ketika entitas tidak dalam bentuk objek/grafik. Oleh karena itu, sering kali bersifat pragmatis untuk menyimpan properti foreign key dalam tipe .NET untuk tujuan ini. Properti kunci asing dapat bersifat privat, yang merupakan kompromi yang baik untuk mencegah ekspos kunci asing namun tetap memungkinkan perjalanan nilainya bersama entitas.

Properti kunci asing bayangan sering dibuat oleh konvensi. Kunci asing bayangan juga akan dibuat jika argumen ke HasForeignKey tidak cocok dengan properti .NET mana pun. Contohnya:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey("MyBlogId");
}

Menurut konvensi, kunci asing bayangan mendapatkan jenisnya dari kunci pokok dalam suatu relasi. Jenis ini dibuat nullable kecuali hubungan terdeteksi sebagai atau dikonfigurasi sesuai kebutuhan.

Properti kunci asing bayangan juga dapat dibuat secara eksplisit, yang berguna untuk mengonfigurasi aspek properti tersebut. Misalnya, untuk membuat properti tidak dapat diubah ke null:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .Property<string>("MyBlogId")
        .IsRequired();

    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey("MyBlogId");
}

Petunjuk / Saran

Menurut konvensi, properti kunci asing mewarisi faset seperti panjang maksimum dan dukungan Unicode dari kunci utama dalam relasi. Oleh karena itu jarang diperlukan untuk secara eksplisit mengonfigurasi faset pada properti kunci asing.

Pembuatan properti bayangan jika nama yang diberikan tidak cocok dengan properti apa pun dari jenis entitas dapat dinonaktifkan menggunakan ConfigureWarnings. Contohnya:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.ConfigureWarnings(b => b.Throw(CoreEventId.ShadowPropertyCreated));

Nama batasan kunci asing

Berdasarkan konvensi batasan kunci asing diberi nama FK_<dependent type name>_<principal type name>_<foreign key property name>. Untuk kunci asing komposit, <foreign key property name> menjadi daftar nama properti kunci asing yang dipisahkan garis bawah.

Ini dapat diubah dalam API pembuatan model menggunakan HasConstraintName. Contohnya:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.BlogId)
        .HasConstraintName("My_BlogId_Constraint");
}

Petunjuk / Saran

Nama batasan tidak digunakan oleh runtime EF. Ini hanya digunakan saat membuat skema database menggunakan Migrasi Inti EF.

Indeks untuk kunci asing

Menurut konvensi, EF membuat indeks database untuk atribut atau atribut dari kunci asing. Lihat Konvensi pembuatan model untuk informasi selengkapnya tentang jenis indeks yang dibuat oleh konvensi.

Petunjuk / Saran

Hubungan didefinisikan dalam model EF antara jenis entitas yang disertakan dalam model tersebut. Beberapa hubungan mungkin perlu mereferensikan jenis entitas dalam model konteks yang berbeda--misalnya, saat menggunakan pola BoundedContext. Dalam situasi ini, kolom kunci asing harus dipetakan ke properti normal, dan properti ini kemudian dapat dimanipulasi secara manual untuk menangani perubahan pada hubungan.

Kunci utama

Menurut konvensi, kunci asing dibatasi oleh kunci utama di ujung utama hubungan. Namun, kunci alternatif dapat digunakan sebagai gantinya. Ini dicapai menggunakan HasPrincipalKey pada API pembuatan model. Misalnya, untuk satu kunci asing properti:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasPrincipalKey(e => e.AlternateId);
}

Atau untuk kunci asing komposit dengan beberapa properti:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasPrincipalKey(e => new { e.AlternateId1, e.AlternateId2 });
}

HasPrincipalKey juga dapat diteruskan nama properti kunci alternatif sebagai string. Misalnya, untuk satu kunci properti:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasPrincipalKey("AlternateId");
}

Atau, untuk kunci komposit:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasPrincipalKey("AlternateId1", "AlternateId2");
}

Nota

Urutan properti dalam kunci utama dan kunci asing harus sesuai. Ini juga merupakan urutan di mana kunci didefinisikan dalam skema database. Ini tidak harus sama dengan urutan properti dalam jenis entitas atau kolom dalam tabel.

Tidak perlu memanggil HasAlternateKey untuk menentukan kunci alternatif pada entitas utama; ini dilakukan secara otomatis ketika HasPrincipalKey digunakan dengan properti yang bukan properti kunci utama. Namun, HasAlternateKey dapat digunakan untuk mengonfigurasi kunci alternatif lebih lanjut, seperti untuk mengatur nama batasan databasenya. Lihat Kunci untuk informasi selengkapnya.

Hubungan dengan entitas tanpa kunci

Setiap hubungan harus memiliki kunci asing yang mereferensikan kunci utama (primer atau alternatif). Ini berarti bahwa jenis entitas tanpa kunci tidak dapat bertindak sebagai akhir utama hubungan, karena tidak ada kunci utama bagi kunci asing untuk dirujuk.

Petunjuk / Saran

Jenis entitas tidak dapat memiliki kunci alternatif tetapi tidak ada kunci primer. Dalam hal ini, kunci alternatif (atau salah satu kunci alternatif, jika ada beberapa) harus dipromosikan ke kunci primer.

Namun, jenis entitas tanpa kunci masih dapat memiliki kunci asing yang ditentukan, dan karenanya dapat bertindak sebagai akhir hubungan dependen. Misalnya, pertimbangkan jenis ini, di mana Tag tidak memiliki kunci:

public class Tag
{
    public string Text { get; set; } = null!;
    public int PostId { get; set; }
    public Post Post { get; set; } = null!;
}

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

Tag dapat dikonfigurasi pada ujung hubungan yang bergantung.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Tag>()
        .HasNoKey();

    modelBuilder.Entity<Post>()
        .HasMany<Tag>()
        .WithOne(e => e.Post);
}

Nota

EF tidak mendukung navigasi yang menunjuk ke jenis entitas tanpa kunci. Lihat Masalah GitHub #30331.

Kunci asing dalam relasi banyak ke banyak

Dalam hubungan banyak ke banyak, kunci asing didefinisikan pada jenis entitas gabungan dan dipetakan ke batasan kunci asing dalam tabel gabungan. Semua yang dijelaskan di atas juga dapat diterapkan pada kunci asing entitas gabungan ini. Misalnya, mengatur nama batasan database:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .HasMany(e => e.Tags)
        .WithMany(e => e.Posts)
        .UsingEntity(
            l => l.HasOne(typeof(Tag)).WithMany().HasConstraintName("TagForeignKey_Constraint"),
            r => r.HasOne(typeof(Post)).WithMany().HasConstraintName("PostForeignKey_Constraint"));
}