Generowane wartości

Kolumny bazy danych mogą mieć wygenerowane wartości na różne sposoby: kolumny klucza podstawowego są często automatycznie zwiększane liczby całkowite, inne kolumny mają wartości domyślne lub obliczone itp. Ta strona zawiera szczegółowe informacje o różnych wzorcach generowania wartości konfiguracji za pomocą programu EF Core.

Wartości domyślne

W relacyjnych bazach danych można skonfigurować kolumnę z wartością domyślną; Jeśli wiersz zostanie wstawiony bez wartości dla tej kolumny, zostanie użyta wartość domyślna.

Wartość domyślną właściwości można skonfigurować:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Rating)
        .HasDefaultValue(3);
}

Można również określić fragment SQL, który jest używany do obliczania wartości domyślnej:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Created)
        .HasDefaultValueSql("getdate()");
}

Obliczone kolumny

W większości relacyjnych baz danych kolumnę można skonfigurować tak, aby jej wartość została obliczona w bazie danych, zwykle z wyrażeniem odwołującym się do innych kolumn:

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

Powyższe polecenie tworzy wirtualną obliczoną kolumnę, której wartość jest obliczana za każdym razem, gdy jest pobierana z bazy danych. Można również określić, że kolumna obliczeniowa jest przechowywana (czasami nazywana utrwalone), co oznacza, że jest obliczana na każdej aktualizacji wiersza i jest przechowywana na dysku obok zwykłych kolumn:

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

Klucze podstawowe

Zgodnie z konwencją klucze podstawowe typu krótkie, int, długie lub guid są skonfigurowane tak, aby wartości generowane dla wstawionych jednostek, jeśli wartość nie jest dostarczana przez aplikację. Dostawca bazy danych zwykle zajmuje się niezbędną konfiguracją; na przykład numeryczny klucz podstawowy w programie SQL Server jest automatycznie konfigurowany jako kolumna IDENTITY.

Aby uzyskać więcej informacji, zobacz dokumentację dotyczącą kluczy i wskazówek dotyczących określonych strategii mapowania dziedziczenia.

Jawne konfigurowanie generowania wartości

Widzieliśmy powyżej, że program EF Core automatycznie konfiguruje generowanie wartości dla kluczy podstawowych — ale możemy chcieć wykonać to samo w przypadku właściwości innych niż klucz. Możesz skonfigurować dowolną właściwość tak, aby jej wartość została wygenerowana dla wstawionych jednostek w następujący sposób:

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

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

Podobnie właściwość można skonfigurować tak, aby jej wartość została wygenerowana w dodatku lub aktualizacji:

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

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

W przeciwieństwie do wartości domyślnych lub kolumn obliczeniowych nie określamy sposobu generowania wartości, które zależą od używanego dostawcy bazy danych. Dostawcy baz danych mogą automatycznie konfigurować generowanie wartości dla niektórych typów właściwości, ale inni mogą wymagać ręcznego skonfigurowania sposobu generowania wartości.

Na przykład w programie SQL Server, gdy właściwość identyfikatora GUID jest skonfigurowana jako klucz podstawowy, dostawca automatycznie wykonuje generowanie wartości po stronie klienta przy użyciu algorytmu w celu wygenerowania optymalnych wartości sekwencyjnych identyfikatorów GUID. Jednak określenie ValueGeneratedOnAdd właściwości DateTime nie będzie miało żadnego wpływu (zobacz poniższą sekcję generowania wartości DateTime).

Podobnie właściwości bajtu[] skonfigurowane jako wygenerowane podczas dodawania lub aktualizacji i oznaczone jako tokeny współbieżności są konfigurowane z typem danych rowversion, dzięki czemu wartości są generowane automatycznie w bazie danych. Jednak określenie ValueGeneratedOnAdd nie ma żadnego wpływu.

Zapoznaj się z dokumentacją dostawcy dotyczącą technik generowania określonych wartości, które obsługuje. Dokumentację generowania wartości programu SQL Server można znaleźć tutaj.

Generowanie wartości daty/godziny

Typowym żądaniem jest posiadanie kolumny bazy danych zawierającej datę/godzinę pierwszego wstawienia wiersza (wartość wygenerowaną podczas dodawania) lub czas ostatniej aktualizacji (wartość wygenerowana podczas dodawania lub aktualizacji). Ponieważ istnieją różne strategie do wykonania, dostawcy platformy EF Core zwykle nie konfigurują generowania wartości automatycznie dla kolumn daty/godziny — musisz to skonfigurować samodzielnie.

Sygnatura czasowa tworzenia

Skonfigurowanie kolumny daty/godziny w celu utworzenia znacznika czasu wiersza jest zwykle kwestią konfigurowania wartości domyślnej przy użyciu odpowiedniej funkcji SQL. Na przykład w programie SQL Server można użyć następujących elementów:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Created)
        .HasDefaultValueSql("getdate()");
}

Pamiętaj, aby wybrać odpowiednią funkcję, ponieważ może istnieć kilka (np. GETDATE()GETUTCDATE()).

Sygnatura czasowa aktualizacji

Chociaż przechowywane kolumny obliczeniowe wydają się dobrym rozwiązaniem do zarządzania znacznikami czasu ostatniej aktualizacji, bazy danych zwykle nie zezwalają na określanie funkcji, takich jak GETDATE() w kolumnie obliczeniowej. Alternatywnie możesz skonfigurować wyzwalacz bazy danych, aby osiągnąć ten sam efekt:

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

Aby uzyskać informacje na temat tworzenia wyzwalaczy, zobacz dokumentację dotyczącą używania nieprzetworzonego języka SQL w migracjach.

Zastępowanie generowania wartości

Mimo że właściwość jest skonfigurowana do generowania wartości, w wielu przypadkach nadal można jawnie określić dla niej wartość. To, czy rzeczywiście będzie działać, zależy od określonego mechanizmu generowania wartości, który został skonfigurowany; Chociaż można określić jawną wartość zamiast używać wartości domyślnej kolumny, nie można tego samego zrobić z obliczonymi kolumnami.

Aby zastąpić generowanie wartości jawną wartością, wystarczy ustawić właściwość na dowolną wartość, która nie jest wartością domyślną CLR dla typu tej właściwości (null dla string, 0 dla int, dla , Guid.Empty itp Guid.).

Uwaga

Próba wstawienia jawnych wartości do tożsamości programu SQL Server domyślnie kończy się niepowodzeniem; Zapoznaj się z tymi dokumentami, aby uzyskać obejście problemu.

Aby podać jawną wartość właściwości, które zostały skonfigurowane jako wartość wygenerowana podczas dodawania lub aktualizacji, należy również skonfigurować właściwość w następujący sposób:

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

Brak generowania wartości

Oprócz określonych scenariuszy, takich jak opisane powyżej, właściwości zwykle nie mają skonfigurowanej generowania wartości; Oznacza to, że aplikacja musi zawsze podać wartość do zapisania w bazie danych. Ta wartość musi zostać przypisana do nowych jednostek, zanim zostaną dodane do kontekstu.

Jednak w niektórych przypadkach możesz wyłączyć generowanie wartości skonfigurowane zgodnie z konwencją. Na przykład klucz podstawowy typu int jest zwykle niejawnie konfigurowany jako wartość wygenerowana do dodania (np. kolumna tożsamości w programie SQL Server). Można to wyłączyć za pomocą następujących opcji:

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

    public string Url { get; set; }
}