Vygenerované hodnoty

Databázové sloupce můžou mít různé hodnoty vygenerované různými způsoby: sloupce primárního klíče často automaticky navyšují celá čísla, jiné sloupce mají výchozí nebo vypočítané hodnoty atd. Tato stránka podrobně popisuje různé vzory generování hodnot konfigurace pomocí EF Core.

Výchozí hodnoty

U relačních databází lze sloupec nakonfigurovat s výchozí hodnotou; pokud je řádek vložen bez hodnoty pro tento sloupec, použije se výchozí hodnota.

U vlastnosti můžete nakonfigurovat výchozí hodnotu:

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

Můžete také zadat fragment SQL, který se používá k výpočtu výchozí hodnoty:

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

Počítané sloupce

U většiny relačních databází je možné sloupec nakonfigurovat tak, aby se jeho hodnota počítala v databázi, obvykle s výrazem odkazujícím na jiné sloupce:

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

Výše uvedený příklad vytvoří virtuální počítaný sloupec, jehož hodnota se vypočítá při každém načtení z databáze. Můžete také určit, že se počítaný sloupec uloží (někdy označovaný jako trvalý), což znamená, že se vypočítá při každé aktualizaci řádku a uloží se na disk spolu s běžnými sloupci:

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

Primární klíče

Podle konvence jsou nesložené primární klíče typu short, int, long nebo Guid nastaveny tak, aby měly hodnoty vygenerované pro vložené entity, pokud aplikace hodnotu neposkytuje. Poskytovatel databáze se obvykle stará o potřebnou konfiguraci; Například číselný primární klíč v SQL Serveru se automaticky nastaví jako sloupec IDENTITY.

Další informace najdete v dokumentaci ke klíčům a doprovodným materiálům pro konkrétní strategie mapování dědičnosti.

Explicitní konfigurace generování hodnot

Výše jsme viděli, že EF Core automaticky nastavuje generování hodnot pro primární klíče, ale pro vlastnosti, které nejsou klíči, můžeme udělat totéž. Libovolnou vlastnost můžete nakonfigurovat tak, aby měla hodnotu vygenerovanou pro vložené entity následujícím způsobem:

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

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

Podobně lze vlastnost nakonfigurovat tak, aby měla hodnotu vygenerovanou při přidání nebo aktualizaci:

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

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

Na rozdíl od výchozích hodnot nebo počítaných sloupců nezadáváme způsob generování hodnot. To závisí na používaném poskytovateli databáze. Poskytovatelé databází můžou pro některé typy vlastností automaticky nastavit generování hodnot, jiné ale můžou vyžadovat ruční nastavení způsobu generování hodnoty.

Pokud je například vlastnost GUID nakonfigurovaná jako primární klíč, poskytovatel automaticky provádí generování hodnot na straně klienta pomocí algoritmu k vygenerování optimálních sekvenčních hodnot GUID. Zadání ValueGeneratedOnAdd vlastnosti DateTime však nebude mít žádný vliv (viz část níže pro generování hodnot DateTime).

Podobně jsou vlastnosti bajtů[] nakonfigurované jako vygenerované při přidání nebo aktualizaci a označené jako tokeny souběžnosti nastaveny s datovým typem rowversion, aby se hodnoty automaticky vygenerovaly v databázi. Zadávání ValueGeneratedOnAdd však nemá žádný vliv.

Konkrétní techniky generování hodnot, které podporuje, najdete v dokumentaci poskytovatele. Dokumentaci ke generování hodnot SQL Serveru najdete tady.

Generování hodnot data a času

Běžným požadavkem je mít sloupec databáze, který obsahuje datum a čas prvního vložení řádku (hodnota vygenerovaná při přidání) nebo datum poslední aktualizace (hodnota vygenerovaná při přidání nebo aktualizaci). Vzhledem k tomu, že existují různé strategie, poskytovatelé EF Core obvykle pro sloupce s datem a časem nenastavují generování hodnot automaticky – musíte to nakonfigurovat sami.

Časové razítko vytvoření

Konfigurace sloupce data a času tak, aby měla časové razítko vytvoření řádku, je obvykle otázkou konfigurace výchozí hodnoty s příslušnou funkcí SQL. Například na SQL Serveru můžete použít následující:

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

Nezapomeňte vybrat příslušnou funkci, protože může existovat několik (např. GETDATE() vs. GETUTCDATE()).

Časové razítko aktualizace

I když uložené počítané sloupce vypadají jako vhodné řešení pro správu časových razítek poslední aktualizace, databáze obvykle neumožňují zadávání funkcí, jako GETDATE() je například ve vypočítaném sloupci. Jako alternativu můžete nastavit trigger databáze tak, aby dosáhl stejného efektu:

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

Informace o vytváření triggerů najdete v dokumentaci k použití nezpracovaného SQL v migracích.

Přepsání generování hodnot

I když je vlastnost nakonfigurovaná pro generování hodnot, v mnoha případech pro ni můžete explicitně zadat hodnotu. Zda to bude skutečně fungovat, závisí na konkrétním mechanismu generování hodnot, který byl nakonfigurován; i když můžete místo výchozí hodnoty sloupce zadat explicitní hodnotu, nelze to samé provést s vypočítanými sloupci.

Chcete-li přepsat generování hodnot explicitní hodnotou, jednoduše nastavte vlastnost na libovolnou hodnotu, která není výchozí hodnotou CLR pro tento typ vlastnosti (null pro , 0 pro intstring, Guid.Empty pro Guidatd.).

Poznámka:

Pokus o vložení explicitních hodnot do IDENTITY SQL Serveru ve výchozím nastavení selže; Alternativní řešení najdete v těchto dokumentech.

Chcete-li poskytnout explicitní hodnotu pro vlastnosti, které byly nakonfigurovány jako hodnota vygenerovaná při přidání nebo aktualizaci, musíte také nakonfigurovat vlastnost následujícím způsobem:

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

Bez generování hodnot

Kromě konkrétních scénářů, jako jsou ty, které jsou popsány výše, vlastnosti obvykle nemají nakonfigurované žádné generování hodnot; to znamená, že je na aplikaci vždy zadat hodnotu, která se má uložit do databáze. Tato hodnota musí být přiřazena novým entitěm, než se přidají do kontextu.

V některých případech ale můžete chtít zakázat generování hodnot, které byly nastaveny konvencí. Například primární klíč typu int je obvykle implicitně nakonfigurovaný jako doplněk generovaný hodnotou (např. sloupec identity na SQL Serveru). Můžete to zakázat pomocí následujících možností:

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

    public string Url { get; set; }
}