Kerangka Kerja Entitas - API Lancar

Fluent API adalah cara lanjutan untuk menentukan konfigurasi model yang mencakup semua hal yang dapat dilakukan anotasi data selain beberapa konfigurasi lanjutan yang tidak dapat dilakukan dengan anotasi data. Anotasi data dan fluent API dapat digunakan bersama-sama, tetapi Code First mendahulukan Fluent API> anotasi data> konvensi default.

  • Fluent API adalah cara lain untuk mengonfigurasi kelas domain Anda.

  • Code First Fluent API paling sering diakses dengan mengganti metode OnModelCreating pada DbContext turunan Anda.

  • Fluent API menyediakan lebih banyak fungsionalitas untuk konfigurasi daripada DataAnnotations. Fluent API mendukung jenis pemetaan berikut.

Pada bab ini, kita akan melanjutkan dengan contoh sederhana yang berisi kelas Mahasiswa, Kursus dan Pendaftaran dan satu kelas konteks dengan nama MyContext seperti yang ditunjukkan pada kode berikut.

using System.Data.Entity; 
using System.Linq; 
using System.Text;
using System.Threading.Tasks;  

namespace EFCodeFirstDemo {

   class Program {
      static void Main(string[] args) {}
   }
   
   public enum Grade {
      A, B, C, D, F
   }

   public class Enrollment {
      public int EnrollmentID { get; set; }
      public int CourseID { get; set; }
      public int StudentID { get; set; }
      public Grade? Grade { get; set; }
		
      public virtual Course Course { get; set; }
      public virtual Student Student { get; set; }
   }

   public class Student {
      public int ID { get; set; }
      public string LastName { get; set; }
      public string FirstMidName { get; set; }
		
      public DateTime EnrollmentDate { get; set; }
		
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }

   public class Course {
      public int CourseID { get; set; }
      public string Title { get; set; }
      public int Credits { get; set; }
		
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }

   public class MyContext : DbContext {
      public virtual DbSet<Course> Courses { get; set; }
      public virtual DbSet<Enrollment> Enrollments { get; set; }
      public virtual DbSet<Student> Students { get; set; }
   }

}

Untuk mengakses Fluent API, Anda perlu mengganti metode OnModelCreating di DbContext. Mari kita lihat contoh sederhana di mana kita akan mengganti nama kolom pada tabel siswa dari FirstMidName menjadi FirstName seperti yang ditunjukkan pada kode berikut.

public class MyContext : DbContext {

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
      .HasColumnName("FirstName");}

      public virtual DbSet<Course> Courses { get; set; }
      public virtual DbSet<Enrollment> Enrollments { get; set; }
      public virtual DbSet<Student> Students { get; set; }
}

DbModelBuilder digunakan untuk memetakan kelas CLR ke skema database. Ini adalah kelas utama dan di mana Anda dapat mengkonfigurasi semua kelas domain Anda. Pendekatan yang berpusat pada kode untuk membangun Model Data Entitas (EDM) ini dikenal sebagai Kode Pertama.

Fluent API menyediakan sejumlah metode penting untuk mengonfigurasi entitas dan propertinya untuk menimpa berbagai konvensi Code First. Berikut ini beberapa di antaranya.

No Sr Nama Metode & Deskripsi
1

ComplexType<TComplexType>

Mendaftarkan tipe sebagai tipe kompleks dalam model dan mengembalikan objek yang dapat digunakan untuk mengonfigurasi tipe kompleks. Metode ini dapat dipanggil beberapa kali untuk tipe yang sama untuk melakukan beberapa baris konfigurasi.

2

Entity<TEntityType>

Mendaftarkan tipe entitas sebagai bagian dari model dan mengembalikan objek yang dapat digunakan untuk mengkonfigurasi entitas. Metode ini dapat dipanggil berkali-kali untuk entitas yang sama untuk melakukan beberapa baris konfigurasi.

3

HasKey<TKey>

Mengonfigurasi properti kunci utama untuk jenis entitas ini.

4

HasMany<TTargetEntity>

Mengonfigurasi banyak hubungan dari jenis entitas ini.

5

HasOptional<TTargetEntity>

Mengonfigurasi hubungan opsional dari jenis entitas ini. Contoh dari tipe entitas akan dapat disimpan ke database tanpa hubungan ini ditentukan. Kunci asing dalam database akan menjadi nullable.

6

HasRequired<TTargetEntity>

Mengonfigurasi hubungan yang diperlukan dari jenis entitas ini. Contoh dari tipe entitas tidak akan dapat disimpan ke database kecuali hubungan ini ditentukan. Kunci asing dalam database akan menjadi non-nullable.

7

Ignore<TProperty>

Mengecualikan properti dari model sehingga tidak akan dipetakan ke database. (Diwariskan dari StructuralTypeConfiguration <TStructuralType>)

8

Property<T>

Mengonfigurasi properti struct yang ditentukan pada jenis ini. (Diwariskan dari StructuralTypeConfiguration <TStructuralType>)

9

ToTable(String)

Mengonfigurasi nama tabel tempat jenis entitas ini dipetakan.

Fluent API memungkinkan Anda mengonfigurasi entitas atau propertinya, apakah Anda ingin mengubah sesuatu tentang bagaimana mereka memetakan ke database atau bagaimana mereka berhubungan satu sama lain. Ada banyak variasi pemetaan dan pemodelan yang dapat Anda ubah menggunakan konfigurasi. Berikut adalah jenis pemetaan utama yang didukung oleh Fluent API -

  • Pemetaan Entitas
  • Pemetaan Properti

Pemetaan Entitas

Pemetaan entitas hanyalah beberapa pemetaan sederhana yang akan memengaruhi pemahaman Entity Framework tentang bagaimana kelas dipetakan ke database. Semua ini kita diskusikan dalam anotasi data dan di sini kita akan melihat bagaimana mencapai hal yang sama menggunakan Fluent API.

  • Jadi daripada masuk ke kelas domain untuk menambahkan konfigurasi ini, kita bisa melakukan ini di dalam konteks.

  • Hal pertama adalah mengganti metode OnModelCreating, yang memberikan modelBuilder untuk digunakan.

Skema Default

Skema default adalah dbo saat database dibuat. Anda dapat menggunakan metode HasDefaultSchema di DbModelBuilder untuk menentukan skema database yang akan digunakan untuk semua tabel, prosedur tersimpan, dll.

Mari kita lihat contoh berikut di mana skema admin diterapkan.

public class MyContext : DbContext {
   public MyContext() : base("name = MyContextDB") {}

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      //Configure default schema
      modelBuilder.HasDefaultSchema("Admin");
   }
	
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

Memetakan Entitas ke Tabel

Dengan konvensi default, Code First akan membuat tabel database dengan nama properti DbSet di kelas konteks seperti Kursus, Pendaftaran, dan Siswa. Tetapi jika Anda menginginkan nama tabel yang berbeda, Anda dapat mengganti konvensi ini dan dapat memberikan nama tabel yang berbeda dari properti DbSet, seperti yang ditunjukkan pada kode berikut.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Map entity to table
   modelBuilder.Entity<Student>().ToTable("StudentData");
   modelBuilder.Entity<Course>().ToTable("CourseDetail");
   modelBuilder.Entity<Enrollment>().ToTable("EnrollmentInfo");
}

Ketika database dibuat, Anda akan melihat nama tabel seperti yang ditentukan dalam metode OnModelCreating.

Pemisahan Entitas (Memetakan Entitas ke Beberapa Tabel)

Pemisahan Entitas memungkinkan Anda menggabungkan data yang berasal dari beberapa tabel ke dalam satu kelas dan hanya dapat digunakan dengan tabel yang memiliki hubungan satu-ke-satu di antara mereka. Mari kita lihat contoh berikut di mana informasi siswa dipetakan ke dalam dua tabel.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Map entity to table
   modelBuilder.Entity<Student>().Map(sd ⇒ {
      sd.Properties(p ⇒ new { p.ID, p.FirstMidName, p.LastName });
      sd.ToTable("StudentData");
   })

   .Map(si ⇒ {
      si.Properties(p ⇒ new { p.ID, p.EnrollmentDate });
      si.ToTable("StudentEnrollmentInfo");
   });

   modelBuilder.Entity<Course>().ToTable("CourseDetail");
   modelBuilder.Entity<Enrollment>().ToTable("EnrollmentInfo");
}

Pada kode di atas, Anda dapat melihat bahwa entitas Mahasiswa dibagi menjadi dua tabel berikut dengan memetakan beberapa properti ke tabel StudentData dan beberapa properti ke tabel StudentEnrollmentInfo menggunakan metode Peta.

  • StudentData - Berisi Nama Depan dan Nama Belakang Siswa.

  • StudentEnrollmentInfo - Berisi EnrollmentDate.

Saat database dibuat, Anda melihat tabel berikut di database Anda seperti yang diperlihatkan dalam gambar berikut.

Pemetaan Properti

Metode Properti digunakan untuk mengonfigurasi atribut untuk setiap properti milik entitas atau tipe kompleks. Metode Properti digunakan untuk mendapatkan objek konfigurasi untuk properti tertentu. Anda juga dapat memetakan dan mengonfigurasi properti kelas domain Anda menggunakan Fluent API.

Mengonfigurasi Kunci Utama

Konvensi default untuk kunci utama adalah -

  • Kelas mendefinisikan properti yang namanya "ID" atau "Id"
  • Nama kelas diikuti dengan "ID" atau "Id"

Jika kelas Anda tidak mengikuti konvensi default untuk kunci utama seperti yang diperlihatkan dalam kode kelas siswa berikut -

public class Student {
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Kemudian untuk secara eksplisit mengatur properti menjadi kunci utama, Anda dapat menggunakan metode HasKey seperti yang ditunjukkan pada kode berikut -

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");
	
   // Configure Primary Key
   modelBuilder.Entity<Student>().HasKey<int>(s ⇒ s.StdntID); 
}

Konfigurasi Kolom

Dalam Entity Framework, secara default Code First akan membuat kolom untuk properti dengan nama, urutan, dan tipe data yang sama. Tapi Anda juga bisa mengganti konvensi ini, seperti yang ditunjukkan pada kode berikut.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Configure EnrollmentDate Column
   modelBuilder.Entity<Student>().Property(p ⇒ p.EnrollmentDate)
	
   .HasColumnName("EnDate")
   .HasColumnType("DateTime")
   .HasColumnOrder(2);
}

Konfigurasikan Properti MaxLength

Dalam contoh berikut, properti Judul Kursus tidak boleh lebih dari 24 karakter. Ketika pengguna menentukan nilai lebih dari 24 karakter, maka pengguna akan mendapatkan pengecualian DbEntityValidationException.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");
   modelBuilder.Entity<Course>().Property(p ⇒ p.Title).HasMaxLength(24);
}

Konfigurasikan Properti Null atau NotNull

Dalam contoh berikut, properti Judul Kursus diperlukan sehingga metode IsRequired digunakan untuk membuat kolom NotNull. Demikian pula, Student EnrollmentDate bersifat opsional sehingga kami akan menggunakan metode IsOptional untuk mengizinkan nilai null di kolom ini seperti yang ditunjukkan pada kode berikut.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");
   modelBuilder.Entity<Course>().Property(p ⇒ p.Title).IsRequired();
   modelBuilder.Entity<Student>().Property(p ⇒ p.EnrollmentDate).IsOptional();
	
   //modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
   //.HasColumnName("FirstName"); 
}

Mengonfigurasi Hubungan

Hubungan, dalam konteks database, adalah situasi yang ada di antara dua tabel database relasional, ketika satu tabel memiliki kunci asing yang mereferensikan kunci utama dari tabel lainnya. Saat bekerja dengan Code First, Anda menentukan model Anda 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 banyak kasus Anda bisa mengandalkan Code First untuk mengatur hubungan antara tabel Anda berdasarkan foreign key dan properti navigasi.

  • Jika mereka tidak memenuhi konvensi tersebut, ada juga konfigurasi yang dapat Anda gunakan untuk memengaruhi hubungan antar kelas dan bagaimana hubungan tersebut direalisasikan dalam database saat Anda menambahkan konfigurasi di Code First.

  • Beberapa di antaranya tersedia dalam anotasi data dan Anda dapat menerapkan beberapa yang lebih rumit lagi dengan Fluent API.

Konfigurasikan Hubungan Satu-ke-Satu

Saat Anda mendefinisikan hubungan satu-ke-satu dalam model Anda, Anda menggunakan properti navigasi referensi di setiap kelas. Dalam database, kedua tabel hanya dapat memiliki satu record di kedua sisi hubungan. Setiap nilai kunci utama hanya berhubungan dengan satu catatan (atau tidak ada catatan) dalam tabel terkait.

  • Hubungan satu-ke-satu dibuat jika kedua kolom terkait adalah kunci utama atau memiliki batasan unik.

  • Dalam hubungan satu-ke-satu, kunci utama bertindak sebagai kunci asing dan tidak ada kolom kunci asing terpisah untuk tabel mana pun.

  • Jenis hubungan ini tidak umum karena sebagian besar informasi yang terkait dengan cara ini semuanya akan berada dalam satu tabel.

Mari kita lihat contoh berikut di mana kita akan menambahkan kelas lain ke dalam model kita untuk membuat hubungan satu-ke-satu.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual StudentLogIn StudentLogIn { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class StudentLogIn {
   [Key, ForeignKey("Student")]
   public int ID { get; set; }
   public string EmailID { get; set; }
   public string Password { get; set; }
	
   public virtual Student Student { get; set; }
}

Seperti yang Anda lihat pada kode di atas bahwa atribut Key dan ForeignKey digunakan untuk properti ID di kelas StudentLogIn, untuk menandainya sebagai Primary Key dan juga Foreign Key.

Untuk mengonfigurasi hubungan satu-ke-nol atau satu antara Student dan StudentLogIn menggunakan Fluent API, Anda perlu mengganti metode OnModelCreating seperti yang ditunjukkan pada kode berikut.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure ID as PK for StudentLogIn
   modelBuilder.Entity<StudentLogIn>()
   .HasKey(s ⇒ s.ID);

   // Configure ID as FK for StudentLogIn
   modelBuilder.Entity<Student>()
   
   .HasOptional(s ⇒ s.StudentLogIn) //StudentLogIn is optional
   .WithRequired(t ⇒ t.Student); // Create inverse relationship
}

Dalam banyak kasus, Kerangka Entitas dapat menyimpulkan tipe mana yang dependen dan mana yang menjadi prinsipal dalam suatu hubungan. Namun, jika kedua ujung hubungan diperlukan atau kedua sisi bersifat opsional, Kerangka Kerja Entitas tidak dapat mengidentifikasi dependen dan prinsipal. Jika kedua ujung hubungan diperlukan, Anda dapat menggunakan HasRequired seperti yang ditunjukkan pada kode berikut.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure ID as PK for StudentLogIn
   modelBuilder.Entity<StudentLogIn>()
   .HasKey(s ⇒ s.ID);

   // Configure ID as FK for StudentLogIn
   modelBuilder.Entity<Student>()
   .HasRequired(r ⇒ r.Student)
   .WithOptional(s ⇒ s.StudentLogIn);  
}

Ketika database dibuat, Anda akan melihat bahwa hubungan dibuat seperti yang ditunjukkan pada gambar berikut.

Konfigurasikan Hubungan Satu ke Banyak

Tabel kunci utama berisi hanya satu rekaman yang terkait dengan tidak ada, satu, atau banyak rekaman dalam tabel terkait. Ini adalah jenis hubungan yang paling umum digunakan.

  • Dalam jenis hubungan ini, baris dalam tabel A dapat memiliki banyak baris yang cocok dalam tabel B, tetapi baris dalam tabel B hanya dapat memiliki satu baris yang cocok dalam tabel A.

  • Kunci asing ditentukan pada tabel yang mewakili banyak ujung hubungan.

  • Misalnya, pada diagram di atas tabel Siswa dan Pendaftaran memiliki hubungan satu-tomany, setiap siswa mungkin memiliki banyak pendaftaran, tetapi setiap pendaftaran hanya dimiliki oleh satu siswa.

Di bawah ini adalah Pelajar dan Pendaftaran yang memiliki hubungan satu ke banyak, tetapi kunci asing di tabel Pendaftaran tidak mengikuti konvensi Kode Pertama default.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
	
   //StdntID is not following code first conventions name
   public int StdntID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }
}

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual StudentLogIn StudentLogIn { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Dalam kasus ini, untuk mengonfigurasi hubungan satu-ke-banyak menggunakan Fluent API, Anda perlu menggunakan metode HasForeignKey seperti yang ditunjukkan pada kode berikut.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Configure FK for one-to-many relationship
   modelBuilder.Entity<Enrollment>()

   .HasRequired<Student>(s ⇒ s.Student)
   .WithMany(t ⇒ t.Enrollments)
   .HasForeignKey(u ⇒ u.StdntID);  
}

Ketika database dibuat, Anda akan melihat bahwa hubungan dibuat seperti yang ditunjukkan pada gambar berikut.

Dalam contoh di atas, metode HasRequired menetapkan bahwa properti navigasi Student harus Null. Jadi, Anda harus menetapkan Siswa dengan entitas Pendaftaran setiap kali Anda menambah atau memperbarui Pendaftaran. Untuk menangani ini kita perlu menggunakan metode HasOptional daripada metode HasRequired.

Konfigurasikan Hubungan Banyak ke Banyak

Setiap rekaman di kedua tabel bisa terkait dengan sejumlah rekaman (atau tanpa rekaman) di tabel lain.

  • Anda dapat membuat hubungan seperti itu dengan menentukan tabel ketiga, yang disebut tabel persimpangan, yang kunci utamanya terdiri dari kunci asing dari tabel A dan tabel B.

  • Misalnya, tabel siswa dan tabel kursus memiliki hubungan banyak-ke-banyak.

Berikut adalah kelas Student dan Course dimana Student dan Course memiliki banyak hubungan, karena kedua kelas memiliki properti navigasi Students dan Course yang merupakan kumpulan. Dengan kata lain, satu entitas memiliki kumpulan entitas lain.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Course> Courses { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Student> Students { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Untuk mengonfigurasi hubungan banyak-ke-banyak antara Siswa dan Kursus, Anda dapat menggunakan Fluent API seperti yang diperlihatkan dalam kode berikut.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure many-to-many relationship
   modelBuilder.Entity<Student>()
   .HasMany(s ⇒ s.Courses) 
   .WithMany(s ⇒ s.Students);
}

Konvensi Kode Pertama default digunakan untuk membuat tabel gabungan saat database dibuat. Hasilnya, tabel StudentCourses dibuat dengan kolom Course_CourseID dan Student_ID seperti yang ditunjukkan pada gambar berikut.

Jika Anda ingin menentukan nama tabel gabungan dan nama kolom dalam tabel, Anda perlu melakukan konfigurasi tambahan dengan menggunakan metode Peta.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure many-to-many relationship 
   modelBuilder.Entity<Student>()

   .HasMany(s ⇒ s.Courses)
   .WithMany(s ⇒ s.Students)
   
   .Map(m ⇒ {
      m.ToTable("StudentCoursesTable");
      m.MapLeftKey("StudentID");
      m.MapRightKey("CourseID");
   }); 
}

Anda dapat melihat ketika database dibuat, nama tabel dan kolom dibuat seperti yang ditentukan pada kode di atas.

Kami menyarankan Anda untuk menjalankan contoh di atas dengan cara langkah demi langkah untuk pemahaman yang lebih baik.