Relational Database Modeling: Data Annotations vs Fluent API

Entity Framework adalah framework untuk mempermudah mengakses database. Framework ini awalnya dibangun sebagai bagian dari .NET framework yang hanya dapat digunakan pada platform Microsoft. Tetapi dengan dikembangkannya .NET Core yang bersifat multiplatform, maka Entity Framework Core juga dapat digunakan pada berbagai platform.

Entity Framework Core atau disingkat EF Core adalah object-relational mapper (OR/M) yang memungkinkan software developer dapat bekerja dengan database dengan object .NET. Hal ini mengurangi kode program untuk mengakses database, karena digantikan oleh class dan method yang telah disediakan oleh framework ini.

Sebagai contoh jika dimiliki tabel seperti pada gambar di bawah ini.

01

Karenan EF “menganut azas” penggunaan OR/M, maka tabel-tabel di atas harus dibuat modelnya dalam bentuk class-class model yang dikenal dengan class entity model.  Jumlah class yang harus dibuat adalah sesuai dengan jumlah tabel.  Pada kasus di atas, artinya harus dibuat 4 class entity sebagai berikut.

Class Authors.

using System;

namespace EFCoreGuestBook.Models
{
public partial class Authors{
public int AuthorID {set; get;}
public String Name {set; get;}
public String Email {set; get;}
}
}

 

Class Categories.

using System;

namespace EFCoreGuestBook.Models
{
public partial class Categories{
public int CategoryID {set; get;}
public String Name {set; get;}
}
}

 

Class Books.

using System;

namespace EFCoreGuestBook.Models
{
public partial class Books{
public int ISBN {set; get;}
public int CategoryID {set; get;}
public String Title {set; get;}
public String Photo {set; get;}
public DateTime PublishDate {set; get;}
public double Price {set; get;}
public int Quantity {set; get;}
}
}

 

Class BooksAuthors.

using System;

namespace EFCoreGuestBook.Models
{
public partial class BooksAuthors{

public int ISBN {set; get;}

public int AuthorID {set; get;}
}
}

 

Setelah class entity model dibuat, maka langkah selanjutnya adalah menentukan class model mana yang akan merepresentasikan suatu table pada database.  Kemudian harus ditentukan juga property-property dari class akan menjadi representasi dari attribut-attribut table yang mana.  Untuk melakukan mapping class dengan table yang ada pada database dapat dilakukan dengan dua cara, yaitu:

  • Data Annotations, cara dilakukan dengan cara menambahkan “atribut” di dalam file class yang telah dibuat di atas.
  • Fluent API, cara ini dilakukan dengan cara menuliskan program terpisah dari class yang telah dibuat di atas.

{Data Annotations}

Untuk menggunakan cara ini, maka pada setiap class entity model di atas harus ditambahkan baris berikut ini.

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

 

Selanjutnya untuk mapping class Categories ke table categories digunakan atribut [Table(“categories”)] yang dituliskan di atas nama class.  Sedangkan untuk memetakan property class CategoryID dengan atribut category_id pada table digunakan atribut [Column(“category_id”)] yang diletakkan di atas baris property CategoryID.  Sedangkan untuk menyatakan property CategoryID sebagai primary key, digunakan attribut [Key].  Sehingga dapat dilihat kode lengkap class Categories sebagai berikut ini.

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace EFCoreGuestBook.Models
{
[Table(“categories”)]
public partial class Categories{
[Key]
[Column(“category_id”)]
public int CategoryID {set; get;}

[Column(“name”)]
public String Name {set; get;}
}
}

 

Tetapi data annotation mempunyai keterbatasan yaitu:

  • Tidak mendukung “computed column” atau kolom yang nilainya dihitung atau ditentukan pada database.
  • Tidak mendukung “sequence”.
  • Tidak mendukung “default value” atau pemberian nilai default jika nilai suatu kolom tidak diberikan.
  • Tidak mendukung “index”.
  • Tidak mendukung “foreign key contraint” yang digunakan untuk relasi antar model.
  • Tidak mendukung “primary key” lebih dari satu.

Untuk menutupi kekurangan tersebut maka dapat digunakan Fluent API.

{Fluent API}

Fluent API adalah cara lain untuk melakukan konfigurasi class entity model untuk melakukan mapping class ke table.  Cara kerja Fluent API ini berbeda dengan cara data annotation yang telah dilakukan di atas.  Cara Fluent API tidak akan menyentuh dan mengubah isi dari class entity model seperti yang dilakukan oleh cara data annotation.  Cara ini akan melakukan mapping dan konfigurasi pada file terpisah.  Biasanya mapping dan konfigurasi dilakukan di dalam file class data context.  Berikut ini adalah contoh class data context untuk mengelola class-class entity model di atas.

   1: using Microsoft.EntityFrameworkCore;

   2: using MySQL.Data.EntityFrameworkCore.Extensions;

   3: using Microsoft.Extensions.Configuration;

   4:

   5: namespace EFCoreGuestBook.Models{

   6:     public class BookStoreDataContext : DbContext

   7:     {

   8:         public static string ConnectionString { get; set; }

   9:

  10:         protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

  11:         {

  12:             optionsBuilder.UseMySQL(ConnectionString);

  13:         }

  14:

  15:         protected override void OnModelCreating(ModelBuilder modelBuilder)

  16:         {

  17:             modelBuilder.Entity<Categories>(entity =>

  18:             {

  19:                 entity.Property(e => e.CategoryID).HasColumnName("category_id");

  20:                 entity.Property(e => e.Name).HasColumnName("name");

  21:             });

  22:             modelBuilder.Entity<Categories>().HasKey(e => new { e.CategoryID});

  23:

  24:             modelBuilder.Entity<Authors>(entity =>

  25:             {

  26:                 entity.Property(e => e.AuthorID).HasColumnName("author_id");

  27:                 entity.Property(e => e.Name).HasColumnName("name");

  28:                 entity.Property(e => e.Email).HasColumnName("email");

  29:             });

  30:             modelBuilder.Entity<Authors>().HasKey(e => new { e.AuthorID});

  31:

  32:             modelBuilder.Entity<Books>(entity =>

  33:             {

  34:                 entity.Property(e => e.ISBN).HasColumnName("isbn");

  35:                 entity.Property(e => e.CategoryID).HasColumnName("category_id");

  36:                 entity.Property(e => e.Title).HasColumnName("title");

  37:                 entity.Property(e => e.Photo).HasColumnName("photo");

  38:                 entity.Property(e => e.PublishDate).HasColumnName("publish_date");

  39:                 entity.Property(e => e.Price).HasColumnName("price");

  40:                 entity.Property(e => e.Quantity).HasColumnName("qty");

  41:             });

  42:             modelBuilder.Entity<Books>().HasKey(e => new { e.ISBN});

  43:

  44:             modelBuilder.Entity<BooksAuthors>(entity =>

  45:             {

  46:                 entity.Property(e => e.ISBN).HasColumnName("isbn");

  47:                 entity.Property(e => e.AuthorID).HasColumnName("author_id");

  48:             });

  49:             modelBuilder.Entity<BooksAuthors>().HasKey(e => new { e.ISBN, e. AuthorID });

  50:         }

  51:         public virtual DbSet<Categories> Categories { get; set; }

  52:         public virtual DbSet<Authors> Authors { get; set; }

  53:         public virtual DbSet<Books> Books { get; set; }

  54:         public virtual DbSet<BooksAuthors> BooksAuthors { get; set; }

  55:     }

  56: }

Pada baris ke-51 sampai dengan baris ke-54 dapat dilihat bagaimana cara memetakan class dengan tabel.  Berikut adalah sintaks dan penjelasan dari keempat baris tersebut.

public virtual DbSet<NAMA_CLASS_ENTITY> NAMA_TABLE { get; set; }

 

Cara lain untuk memetakan class entity dengan table juga dapat dilakukan dengan penulisan kode di dalam method OnModelCreating dengan sintaks sebagai berikut.

modelBuilder.Entity<NAMA_CLASS_ENTITY>().ToTable("NAMA_TABLE");

 

Sehingga untuk melakukan mapping class BooksAuthors dengan table books_authors dapat dilakukan dengan cara berikut.

modelBuilder.Entity<BooksAuthors>().ToTable("books_authors");

 

Kemudian untuk mapping property-property dari class Categories ke atribut-atribut table categories dapat dilihat pada baris ke-19 dan ke-20.  Sedangkan untuk menentukan property mana yang akan menjadi primary key dapat dilihat pada baris ke-22.  Kemudian untuk kasus ketika table memiliki dua primary key seperti tabel books_authors, maka dapat dilihat pada baris ke-49 sebagai cara menentukan lebih dari satu property pada class sebagai primary key.

{Kesimpulan}

Kedua cara di atas dapat digunakan sekaligus dan saling melengkapi.  Tetapi menurut saran saya, agar lebih baik menggunakan Fluent API secara penuh, karena fitur-fitur yang diberikan telah lengkap.  Dan hal itu juga membuat isi class entity lebih bersih karena konfigurasi dilakukan pada file terpisah dan terpusat, yaitu pada file class data context.

Selamat mencoba, semoga bermanfaat.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.