Membuat dan Mengonfigurasi Model
EF Core menggunakan model metadata untuk menjelaskan bagaimana jenis entitas aplikasi dipetakan ke database yang mendasar. Model ini dibangun menggunakan serangkaian konvensi - heuristik yang mencari pola umum. Model kemudian dapat disesuaikan menggunakan atribut pemetaan (juga dikenal sebagai anotasi data) dan/atau panggilan ke ModelBuilder metode (juga dikenal sebagai API fasih) di OnModelCreating, yang keduanya akan mengambil alih konfigurasi yang dilakukan oleh konvensi.
Sebagian besar konfigurasi dapat diterapkan ke model yang menargetkan penyimpanan data apa pun. Penyedia juga dapat mengaktifkan konfigurasi yang khusus untuk penyimpanan data tertentu dan mereka juga dapat mengabaikan konfigurasi yang tidak didukung atau tidak berlaku. Untuk dokumentasi tentang konfigurasi khusus penyedia, lihat bagian Penyedia database.
Tip
Anda dapat melihat sampel artikel ini di GitHub.
Menggunakan API fasih untuk mengonfigurasi model
Anda dapat mengambil OnModelCreating
alih metode dalam konteks turunan Anda dan menggunakan API fasih untuk mengonfigurasi model Anda. Ini adalah metode konfigurasi yang paling canggih dan memungkinkan konfigurasi ditentukan tanpa mengubah kelas entitas. Konfigurasi API fasih memiliki prioritas tertinggi dan akan menggantikan konvensi dan anotasi data. Konfigurasi diterapkan dalam urutan metode dipanggil dan jika ada konflik, panggilan terbaru akan menimpa konfigurasi yang ditentukan sebelumnya.
using Microsoft.EntityFrameworkCore;
namespace EFModeling.EntityProperties.FluentAPI.Required;
internal class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
#region Required
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.Url)
.IsRequired();
}
#endregion
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
Tip
Untuk menerapkan konfigurasi yang sama ke beberapa objek dalam model, lihat konfigurasi massal.
Konfigurasi pengelompokan
Untuk mengurangi ukuran metode OnModelCreating
, semua konfigurasi untuk jenis entitas dapat diekstraksi ke kelas terpisah yang mengimplementasikan IEntityTypeConfiguration<TEntity>.
public class BlogEntityTypeConfiguration : IEntityTypeConfiguration<Blog>
{
public void Configure(EntityTypeBuilder<Blog> builder)
{
builder
.Property(b => b.Url)
.IsRequired();
}
}
Kemudian hanya menggunakan metode Configure
dari OnModelCreating
.
new BlogEntityTypeConfiguration().Configure(modelBuilder.Entity<Blog>());
Menerapkan semua konfigurasi dalam rakitan
Dimungkinkan untuk menerapkan semua konfigurasi yang ditentukan dalam jenis yang menerapkan IEntityTypeConfiguration
dalam rakitan tertentu.
modelBuilder.ApplyConfigurationsFromAssembly(typeof(BlogEntityTypeConfiguration).Assembly);
Catatan
Urutan konfigurasi akan diterapkan tidak ditentukan, oleh karena itu metode ini hanya boleh digunakan jika urutannya tidak menjadi persoalan.
Menggunakan EntityTypeConfigurationAttribute
pada jenis entitas
Alih-alih secara eksplisit memanggil Configure
, dapat EntityTypeConfigurationAttribute ditempatkan pada jenis entitas sehingga EF Core dapat menemukan dan menggunakan konfigurasi yang sesuai. Contohnya:
[EntityTypeConfiguration(typeof(BookConfiguration))]
public class Book
{
public int Id { get; set; }
public string Title { get; set; }
public string Isbn { get; set; }
}
Atribut ini berarti bahwa EF Core akan menggunakan implementasi yang ditentukan IEntityTypeConfiguration
setiap kali Book
jenis entitas disertakan dalam model. Jenis entitas disertakan dalam model menggunakan salah satu mekanisme normal. Misalnya, dengan membuat DbSet<TEntity> properti untuk jenis entitas:
public class BooksContext : DbContext
{
public DbSet<Book> Books { get; set; }
//...
Atau dengan mendaftarkannya di OnModelCreating:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Book>();
}
Catatan
EntityTypeConfigurationAttribute
jenis tidak akan ditemukan secara otomatis dalam rakitan. Jenis entitas harus ditambahkan ke model sebelum atribut akan ditemukan pada jenis entitas tersebut.
Menggunakan anotasi data untuk mengonfigurasi model
Anda juga dapat menerapkan atribut tertentu (dikenal sebagai Anotasi Data) ke kelas dan properti Anda. Anotasi data akan mengambil alih konvensi, tetapi akan ditimpa oleh konfigurasi API Fasih.
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace EFModeling.EntityProperties.DataAnnotations.Annotations;
internal class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
}
[Table("Blogs")]
public class Blog
{
public int BlogId { get; set; }
[Required]
public string Url { get; set; }
}
Konvensi bawaan
EF Core mencakup banyak konvensi pembuatan model yang diaktifkan secara default. Anda dapat menemukan semuanya dalam daftar kelas yang mengimplementasikan IConvention antarmuka. Namun, daftar itu tidak termasuk konvensi yang diperkenalkan oleh penyedia dan plugin database pihak ketiga.
Aplikasi dapat menghapus atau mengganti salah satu konvensi ini, serta menambahkan konvensi kustom baru yang menerapkan konfigurasi untuk pola yang tidak dikenali oleh EF di luar kotak.
Tip
Kode yang ditunjukkan di bawah ini berasal dari ModelBuildingConventionsSample.cs.
Menghapus konvensi yang sudah ada
Terkadang salah satu konvensi bawaan mungkin tidak sesuai untuk aplikasi Anda, dalam hal ini dapat dihapus.
Tip
Jika model Anda tidak menggunakan atribut pemetaan (alias anotasi data) untuk konfigurasi, maka semua konvensi dengan nama yang berakhirannya AttributeConvention
dapat dihapus dengan aman untuk mempercepat pembuatan model.
Contoh: Jangan membuat indeks untuk kolom kunci asing
Biasanya masuk akal untuk membuat indeks untuk kolom kunci asing (FK), dan karenanya ada konvensi bawaan untuk ini: ForeignKeyIndexConvention. Melihat tampilan debug model untuk Post
jenis entitas dengan hubungan ke Blog
dan Author
, kita dapat melihat dua indeks dibuat--satu untuk BlogId
FK, dan yang lainnya untuk AuthorId
FK.
EntityType: Post
Properties:
Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
AuthorId (no field, int?) Shadow FK Index
BlogId (no field, int) Shadow Required FK Index
Navigations:
Author (Author) ToPrincipal Author Inverse: Posts
Blog (Blog) ToPrincipal Blog Inverse: Posts
Keys:
Id PK
Foreign keys:
Post {'AuthorId'} -> Author {'Id'} ToDependent: Posts ToPrincipal: Author ClientSetNull
Post {'BlogId'} -> Blog {'Id'} ToDependent: Posts ToPrincipal: Blog Cascade
Indexes:
AuthorId
BlogId
Namun, indeks memiliki overhead, dan mungkin tidak selalu sesuai untuk membuatnya untuk semua kolom FK. Untuk mencapai hal ini, ForeignKeyIndexConvention
dapat dihapus saat membangun model:
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
configurationBuilder.Conventions.Remove(typeof(ForeignKeyIndexConvention));
}
Melihat tampilan debug model untuk Post
saat ini, kita melihat bahwa indeks pada FK belum dibuat:
EntityType: Post
Properties:
Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
AuthorId (no field, int?) Shadow FK
BlogId (no field, int) Shadow Required FK
Navigations:
Author (Author) ToPrincipal Author Inverse: Posts
Blog (Blog) ToPrincipal Blog Inverse: Posts
Keys:
Id PK
Foreign keys:
Post {'AuthorId'} -> Author {'Id'} ToDependent: Posts ToPrincipal: Author ClientSetNull
Post {'BlogId'} -> Blog {'Id'} ToDependent: Posts ToPrincipal: Blog Cascade
Jika diinginkan, indeks masih dapat dibuat secara eksplisit untuk kolom kunci asing, baik menggunakan IndexAttribute atau dengan konfigurasi di OnModelCreating
.
Tampilan debug
Tampilan debug pembuat model dapat diakses di debugger IDE Anda. Misalnya, dengan Visual Studio:
Ini juga dapat diakses langsung dari kode, misalnya untuk mengirim tampilan debug ke konsol:
Console.WriteLine(context.Model.ToDebugString());
Tampilan debug memiliki bentuk pendek dan bentuk panjang. Bentuk panjang juga mencakup semua anotasi, yang dapat berguna jika Anda perlu melihat metadata relasional atau khusus penyedia. Tampilan panjang juga dapat diakses dari kode:
Console.WriteLine(context.Model.ToDebugString(MetadataDebugStringOptions.LongDefault));