Bagikan melalui


Nilai yang Dihasilkan

Kolom database dapat memiliki nilai yang dihasilkan dengan berbagai cara: kolom kunci utama sering kali menambahkan bilangan bulat secara otomatis, kolom lain memiliki nilai default atau komputasi, dll. Halaman ini merinci berbagai pola untuk pembuatan nilai konfigurasi dengan EF Core.

Nilai baku

Pada database relasional, kolom dapat dikonfigurasi dengan nilai default; jika baris disisipkan tanpa nilai untuk kolom tersebut, nilai default akan digunakan.

Anda dapat mengonfigurasi nilai default pada properti:

modelBuilder.Entity<Blog>()
    .Property(b => b.Rating)
    .HasDefaultValue(3);

Anda juga dapat menentukan fragmen SQL yang digunakan untuk menghitung nilai default:

modelBuilder.Entity<Blog>()
    .Property(b => b.Created)
    .HasDefaultValueSql("getdate()");

Nilai default juga berlaku saat menambahkan kolom baru ke tabel; baris yang sudah ada yang belum memiliki nilai untuk kolom baru akan memiliki nilai default yang ditetapkan padanya.

Nama batasan nilai default

Dimulai dengan EF 10, untuk SQL Server Anda dapat secara eksplisit menentukan nama untuk batasan nilai default, memberi Anda lebih banyak kontrol atas skema database Anda.

modelBuilder.Entity<Blog>()
    .Property(b => b.Rating)
    .HasDefaultValue(3, "DF_Blog_IsActive");
modelBuilder.Entity<Blog>()
    .Property(b => b.Created)
    .HasDefaultValueSql("getdate()" , "DF_Blog_IsActive");

Anda juga dapat memanggil UseNamedDefaultConstraints untuk mengaktifkan penamaan otomatis semua batasan default. Perhatikan bahwa jika Anda memiliki migrasi yang sudah ada, maka migrasi berikutnya yang Anda tambahkan akan mengganti nama setiap batasan default dalam model Anda.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.UseNamedDefaultConstraints();
}

Kolom Terhitung

Pada sebagian besar database relasional, kolom dapat dikonfigurasi agar nilainya dihitung dalam database, biasanya dengan ekspresi yang mengacu pada kolom lain:

modelBuilder.Entity<Person>()
    .Property(p => p.DisplayName)
    .HasComputedColumnSql("[LastName] + ', ' + [FirstName]");

Di atas membuat kolom komputasi virtual , yang nilainya dihitung setiap kali diambil dari database. Anda juga dapat menentukan bahwa kolom komputasi disimpan (kadang-kadang disebut bertahan), yang berarti bahwa kolom tersebut dihitung pada setiap pembaruan baris, dan disimpan pada disk bersama kolom reguler:

modelBuilder.Entity<Person>()
    .Property(p => p.NameLength)
    .HasComputedColumnSql("LEN([LastName]) + LEN([FirstName])", stored: true);

Kunci primer

Berdasarkan konvensi, kunci primer non-komposit jenis short, int, long, atau Guid disiapkan untuk memiliki nilai yang dihasilkan untuk entitas yang disisipkan jika nilai tidak diberikan oleh aplikasi. Penyedia database Anda biasanya mengurus konfigurasi yang diperlukan; misalnya, kunci primer numerik di SQL Server secara otomatis disiapkan menjadi kolom IDENTITY.

Untuk informasi selengkapnya, lihat dokumentasi tentang kunci dan panduan untuk strategi pemetaan pewarisan tertentu.

Mengonfigurasi pembuatan nilai secara eksplisit

Seperti yang telah kita lihat, EF Core secara otomatis mengatur pengaturan nilai untuk kunci primer, tetapi kita mungkin ingin melakukan hal yang sama untuk properti bukan kunci. Anda dapat mengonfigurasi properti apa pun agar nilainya dihasilkan untuk entitas yang disisipkan sebagai berikut:

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public DateTime Inserted { get; set; }
}

Demikian pula, properti dapat dikonfigurasi agar nilainya dihasilkan saat menambahkan atau memperbarui:

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime LastUpdated { get; set; }
}

Tidak seperti nilai default atau kolom komputasi, kami tidak menentukan bagaimana nilai akan dihasilkan; itu tergantung pada penyedia database yang digunakan. Penyedia database dapat secara otomatis menyiapkan pembuatan nilai untuk beberapa jenis properti, tetapi yang lain mungkin mengharuskan Anda menyiapkan secara manual bagaimana nilai dihasilkan.

Misalnya, di SQL Server, ketika properti GUID dikonfigurasi sebagai kunci utama, penyedia secara otomatis melakukan pembuatan nilai sisi klien, menggunakan algoritma untuk menghasilkan nilai GUID berurutan yang optimal. Namun, menentukan ValueGeneratedOnAdd pada properti DateTime tidak akan berpengaruh (lihat bagian di bawah ini untuk pembuatan nilai DateTime).

Demikian pula, properti byte[] yang dikonfigurasi agar dihasilkan saat ditambahkan atau diperbarui dan ditandai sebagai token konkurensi disiapkan dengan tipe data rowversion, sehingga nilai secara otomatis dihasilkan di dalam database. Namun, menentukan ValueGeneratedOnAdd tidak berpengaruh.

Lihat dokumentasi penyedia Anda untuk teknik pembuatan nilai tertentu yang didukungnya. Dokumentasi pembuatan nilai SQL Server dapat ditemukan di sini.

Pembuatan nilai tanggal/waktu

Permintaan umum adalah memiliki kolom database yang berisi tanggal/waktu saat baris pertama kali disisipkan (nilai yang dihasilkan saat ditambahkan), atau kapan terakhir kali diperbarui (nilai yang dihasilkan pada tambahkan atau perbarui). Karena ada berbagai strategi untuk melakukan ini, penyedia EF Core biasanya tidak menyiapkan pembuatan nilai secara otomatis untuk kolom tanggal/waktu - Anda harus mengonfigurasinya sendiri.

Tanda waktu pembuatan

Mengonfigurasi kolom tanggal/waktu untuk memiliki tanda waktu pembuatan baris biasanya merupakan masalah mengonfigurasi nilai default dengan fungsi SQL yang sesuai. Misalnya, di SQL Server Anda dapat menggunakan hal berikut:

modelBuilder.Entity<Blog>()
    .Property(b => b.Created)
    .HasDefaultValueSql("getdate()");

Pastikan untuk memilih fungsi yang sesuai, karena beberapa mungkin ada (misalnya GETDATE() vs. GETUTCDATE()).

Perbarui tanda waktu

Meskipun kolom terhitung yang disimpan tampak seperti solusi yang baik untuk mengelola cap waktu pembaruan terakhir, database biasanya tidak mengizinkan penentuan fungsi seperti GETDATE() di kolom terhitung. Sebagai alternatif, Anda dapat menyiapkan pemicu database untuk mencapai efek yang sama:

CREATE TRIGGER [dbo].[Blogs_UPDATE] ON [dbo].[Blogs]
    AFTER UPDATE
AS
BEGIN
    SET NOCOUNT ON;

    IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;

    UPDATE B
    SET LastUpdated = GETDATE()
    FROM dbo.Blogs AS B
    INNER JOIN INSERTED AS I
        ON B.BlogId = I.BlogId
END

Untuk informasi tentang membuat pemicu, lihat dokumentasi tentang menggunakan SQL mentah dalam migrasi.

Mengesampingkan pembuatan nilai

Meskipun properti dikonfigurasi untuk pembuatan nilai, dalam banyak kasus Anda mungkin masih secara eksplisit menentukan nilai untuknya. Apakah ini akan benar-benar berfungsi tergantung pada mekanisme pembuatan nilai tertentu yang telah dikonfigurasi; meskipun Anda dapat menentukan nilai eksplisit alih-alih menggunakan nilai default kolom, hal yang sama tidak dapat dilakukan dengan kolom komputasi.

Untuk mengambil alih pembuatan nilai dengan nilai eksplisit, cukup atur properti ke nilai apa pun yang bukan nilai default CLR untuk jenis properti tersebut (null untuk string, 0 untuk int, Guid.Empty untuk Guid, dll.).

Nota

Mencoba menyisipkan nilai eksplisit ke dalam IDENTITAS SQL Server gagal secara default; lihat dokumen ini untuk solusinya.

Untuk memberikan nilai eksplisit untuk properti yang telah dikonfigurasi sebagai nilai yang dihasilkan pada penambahan atau pembaruan, Anda juga harus mengonfigurasi properti sebagai berikut:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>().Property(b => b.LastUpdated)
        .ValueGeneratedOnAddOrUpdate()
        .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save);
}

Tidak ada pembuatan nilai

Terlepas dari skenario tertentu seperti yang dijelaskan di atas, properti biasanya tidak memiliki pembuatan nilai yang dikonfigurasi; ini berarti bahwa terserah aplikasi untuk selalu menyediakan nilai yang akan disimpan ke database. Nilai ini harus ditetapkan ke entitas baru sebelum ditambahkan ke konteks.

Namun, dalam beberapa kasus Anda mungkin ingin menonaktifkan pembuatan nilai yang telah disiapkan oleh konvensi. Misalnya, kunci primer tipe int biasanya dikonfigurasi secara implisit sebagai nilai-dihasilkan-saat-penambahan (misalnya kolom identitas di SQL Server). Anda dapat menonaktifkan ini melalui hal berikut:

public class Blog
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int BlogId { get; set; }

    public string Url { get; set; }
}