API Fasih - Hubungan
Catatan
Halaman ini menyediakan informasi tentang menyiapkan hubungan dalam model Code First Anda menggunakan API yang fasih. Untuk informasi umum tentang hubungan di EF dan cara mengakses dan memanipulasi data menggunakan hubungan, lihat Hubungan & Properti Navigasi.
Saat bekerja dengan Code First, Anda menentukan model dengan menentukan kelas CLR domain Anda. Secara default, Entity Framework menggunakan konvensi Code First untuk memetakan kelas Anda ke skema database. Jika Anda menggunakan konvensi penamaan Code First, dalam kebanyakan kasus Anda dapat mengandalkan Code First untuk menyiapkan hubungan antara tabel Anda berdasarkan kunci asing dan properti navigasi yang Anda tentukan pada kelas. Jika Anda tidak mengikuti konvensi saat menentukan kelas, atau jika Anda ingin mengubah cara kerja konvensi, Anda dapat menggunakan API fasih atau anotasi data untuk mengonfigurasi kelas Anda sehingga Code First dapat memetakan hubungan antara tabel Anda.
Pendahuluan
Saat mengonfigurasi hubungan dengan API yang fasih, Anda mulai dengan instans EntityTypeConfiguration lalu menggunakan metode HasRequired, HasOptional, atau HasMany untuk menentukan jenis hubungan yang diikuti entitas ini. Metode HasRequired dan HasOptional mengambil ekspresi lambda yang mewakili properti navigasi referensi. Metode HasMany mengambil ekspresi lambda yang mewakili properti navigasi koleksi. Anda kemudian dapat mengonfigurasi properti navigasi terbalik dengan menggunakan metode WithRequired, WithOptional, dan WithMany. Metode ini memiliki kelebihan beban yang tidak mengambil argumen dan dapat digunakan untuk menentukan kardinalitas dengan navigasi searah.
Anda kemudian dapat mengonfigurasi properti kunci asing dengan menggunakan metode HasForeignKey. Metode ini mengambil ekspresi lambda yang mewakili properti yang akan digunakan sebagai kunci asing.
Mengonfigurasi Hubungan yang Diperlukan-ke-Opsional (Satu-ke-Nol-atau-Satu)
Contoh berikut mengonfigurasi hubungan satu-ke-nol-atau-satu. OfficeAssignment memiliki properti InstructorID yang merupakan kunci primer dan kunci asing, karena nama properti tidak mengikuti konvensi metode HasKey digunakan untuk mengonfigurasi kunci utama.
// Configure the primary key for the OfficeAssignment
modelBuilder.Entity<OfficeAssignment>()
.HasKey(t => t.InstructorID);
// Map one-to-zero or one relationship
modelBuilder.Entity<OfficeAssignment>()
.HasRequired(t => t.Instructor)
.WithOptional(t => t.OfficeAssignment);
Mengonfigurasi Hubungan Di mana Kedua Ujung Diperlukan (Satu-ke-Satu)
Dalam kebanyakan kasus, Entity Framework dapat menyimpulkan jenis mana yang merupakan dependen dan mana yang merupakan utama dalam hubungan. Namun, ketika kedua akhir hubungan diperlukan atau kedua sisi adalah Kerangka Kerja Entitas opsional tidak dapat mengidentifikasi dependen dan utama. Ketika kedua akhir hubungan diperlukan, gunakan WithRequiredPrincipal atau WithRequiredDependent setelah metode HasRequired. Ketika kedua akhir hubungan bersifat opsional, gunakan WithOptionalPrincipal atau WithOptionalDependent setelah metode HasOptional.
// Configure the primary key for the OfficeAssignment
modelBuilder.Entity<OfficeAssignment>()
.HasKey(t => t.InstructorID);
modelBuilder.Entity<Instructor>()
.HasRequired(t => t.OfficeAssignment)
.WithRequiredPrincipal(t => t.Instructor);
Mengonfigurasi Hubungan Banyak ke Banyak
Kode berikut mengonfigurasi hubungan banyak ke banyak antara jenis Kursus dan Instruktur. Dalam contoh berikut, konvensi Code First default digunakan untuk membuat tabel gabungan. Akibatnya tabel CourseInstructor dibuat dengan kolom Course_CourseID dan Instructor_InstructorID.
modelBuilder.Entity<Course>()
.HasMany(t => t.Instructors)
.WithMany(t => t.Courses)
Jika Anda ingin menentukan nama tabel gabungan dan nama kolom dalam tabel, Anda perlu melakukan konfigurasi tambahan dengan menggunakan metode Peta. Kode berikut menghasilkan tabel CourseInstructor dengan kolom CourseID dan InstructorID.
modelBuilder.Entity<Course>()
.HasMany(t => t.Instructors)
.WithMany(t => t.Courses)
.Map(m =>
{
m.ToTable("CourseInstructor");
m.MapLeftKey("CourseID");
m.MapRightKey("InstructorID");
});
Mengonfigurasi Hubungan dengan Satu Properti Navigasi
Hubungan satu arah (juga disebut unidirectional) adalah ketika properti navigasi didefinisikan hanya pada salah satu hubungan berakhir dan bukan pada keduanya. Menurut konvensi, Code First selalu menginterpretasikan hubungan searah sebagai satu-ke-banyak. Misalnya, jika Anda menginginkan hubungan satu-ke-satu antara Instruktur dan OfficeAssignment, di mana Anda memiliki properti navigasi hanya pada jenis Instruktur, Anda perlu menggunakan API fasih untuk mengonfigurasi hubungan ini.
// Configure the primary Key for the OfficeAssignment
modelBuilder.Entity<OfficeAssignment>()
.HasKey(t => t.InstructorID);
modelBuilder.Entity<Instructor>()
.HasRequired(t => t.OfficeAssignment)
.WithRequiredPrincipal();
Mengaktifkan Penghapusan Kaskade
Anda dapat mengonfigurasi penghapusan kaskade pada hubungan dengan menggunakan metode WillCascadeOnDelete. Jika kunci asing pada entitas dependen tidak dapat diubah ke null, maka Kode Pertama menetapkan penghapusan bertingkat pada hubungan. Jika kunci asing pada entitas dependen dapat diubah ke null, Code First tidak mengatur penghapusan bertingkat pada hubungan, dan ketika prinsipal dihapus, kunci asing akan diatur ke null.
Anda dapat menghapus konvensi penghapusan kaskade ini dengan menggunakan:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>()
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>()
Kode berikut mengonfigurasi hubungan yang diperlukan lalu menonaktifkan penghapusan berkala.
modelBuilder.Entity<Course>()
.HasRequired(t => t.Department)
.WithMany(t => t.Courses)
.HasForeignKey(d => d.DepartmentID)
.WillCascadeOnDelete(false);
Mengonfigurasi Kunci Asing Komposit
Jika kunci utama pada jenis Departemen terdiri dari properti DepartmentID dan Name, Anda akan mengonfigurasi kunci utama untuk Departemen dan kunci asing pada jenis Kursus sebagai berikut:
// Composite primary key
modelBuilder.Entity<Department>()
.HasKey(d => new { d.DepartmentID, d.Name });
// Composite foreign key
modelBuilder.Entity<Course>()
.HasRequired(c => c.Department)
.WithMany(d => d.Courses)
.HasForeignKey(d => new { d.DepartmentID, d.DepartmentName });
Mengganti Nama Kunci Asing yang Tidak Ditentukan dalam Model
Jika Anda memilih untuk tidak menentukan kunci asing pada jenis CLR, tetapi ingin menentukan nama apa yang harus dimilikinya dalam database, lakukan hal berikut:
modelBuilder.Entity<Course>()
.HasRequired(c => c.Department)
.WithMany(t => t.Courses)
.Map(m => m.MapKey("ChangedDepartmentID"));
Mengonfigurasi Nama Kunci Asing yang Tidak Mengikuti Konvensi Pertama Kode
Jika properti kunci asing pada kelas Kursus disebut SomeDepartmentID alih-alih DepartmentID, Anda harus melakukan hal berikut untuk menentukan bahwa Anda ingin SomeDepartmentID menjadi kunci asing:
modelBuilder.Entity<Course>()
.HasRequired(c => c.Department)
.WithMany(d => d.Courses)
.HasForeignKey(c => c.SomeDepartmentID);
Model yang Digunakan dalam Sampel
Model Pertama Kode berikut digunakan untuk sampel di halaman ini.
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;
// add a reference to System.ComponentModel.DataAnnotations DLL
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System;
public class SchoolEntities : DbContext
{
public DbSet<Course> Courses { get; set; }
public DbSet<Department> Departments { get; set; }
public DbSet<Instructor> Instructors { get; set; }
public DbSet<OfficeAssignment> OfficeAssignments { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure Code First to ignore PluralizingTableName convention
// If you keep this convention then the generated tables will have pluralized names.
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
public class Department
{
public Department()
{
this.Courses = new HashSet<Course>();
}
// Primary key
public int DepartmentID { get; set; }
public string Name { get; set; }
public decimal Budget { get; set; }
public System.DateTime StartDate { get; set; }
public int? Administrator { get; set; }
// Navigation property
public virtual ICollection<Course> Courses { get; private set; }
}
public class Course
{
public Course()
{
this.Instructors = new HashSet<Instructor>();
}
// Primary key
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
// Foreign key
public int DepartmentID { get; set; }
// Navigation properties
public virtual Department Department { get; set; }
public virtual ICollection<Instructor> Instructors { get; private set; }
}
public partial class OnlineCourse : Course
{
public string URL { get; set; }
}
public partial class OnsiteCourse : Course
{
public OnsiteCourse()
{
Details = new Details();
}
public Details Details { get; set; }
}
public class Details
{
public System.DateTime Time { get; set; }
public string Location { get; set; }
public string Days { get; set; }
}
public class Instructor
{
public Instructor()
{
this.Courses = new List<Course>();
}
// Primary key
public int InstructorID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public System.DateTime HireDate { get; set; }
// Navigation properties
public virtual ICollection<Course> Courses { get; private set; }
}
public class OfficeAssignment
{
// Specifying InstructorID as a primary
[Key()]
public Int32 InstructorID { get; set; }
public string Location { get; set; }
// When Entity Framework sees Timestamp attribute
// it configures ConcurrencyCheck and DatabaseGeneratedPattern=Computed.
[Timestamp]
public Byte[] Timestamp { get; set; }
// Navigation property
public virtual Instructor Instructor { get; set; }
}