Vygenerované hodnoty

Databázové sloupce mohou mít své hodnoty vygenerované různými způsoby: sloupce primárních klíčů jsou často automaticky zvětšující se celá čísla, jiné sloupce mají výchozí nebo vypočítané hodnoty atd. Tato stránka podrobně obsahuje různé vzory generování hodnot konfigurace s EF Core.

Výchozí hodnoty

U relačních databází lze sloupec nakonfigurovat s výchozí hodnotou. Pokud se řádek vloží 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 SQL, který se použije k výpočtu výchozí hodnoty:

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

Vypočítané sloupce

Ve většině relačních databází je možné sloupec nakonfigurovat tak, aby jeho hodnota byla vypočítána v databázi. Obvykle se používá výraz odkazující na ostatní sloupce:

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

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

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

Poznámka

V 5.0 byla přidána podpora pro vytváření uložených EF Core počítané sloupce.

Primární klíče

Podle konvence jsou nesesložené primární klíče typu short, int, long nebo Guid nastavené tak, aby se pro vložené entity generují hodnoty, pokud aplikace hodnotu neposkytne. Poskytovatel databáze se obvykle postará o potřebnou konfiguraci. Například číselný primární klíč v SQL Server se automaticky nastaví jako sloupec IDENTITY.

Další informace najdete v dokumentaci ke klíčům.

Explicitní konfigurace generování hodnot

Výše jsme viděli, EF Core automaticky nastaví generování hodnot pro primární klíče, ale u vlastností, které nejsou klíči, můžeme to udělat stejně. Libovolnou vlastnost můžete nakonfigurovat tak, aby se vygenerovala její hodnota pro vložené entity, a to 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 se při přidání nebo aktualizaci vygenerovala její hodnota:

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

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

Upozornění

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

Pokud je například SQL Server GUID nakonfigurovaná jako hodnota generovaná při přidání, zprostředkovatel automaticky provede generování hodnot na straně klienta pomocí algoritmu k vygenerování optimálních sekvenčních hodnot GUID. Zadání vlastnosti ValueGeneratedOnAdd DateTime ale nebude mít žádný vliv (informace o generování hodnoty DateTime najdete v následující části).

Podobně se vlastnosti byte[] nakonfigurované jako generované při přidání nebo aktualizaci a označené jako tokeny souběžnosti nastaví s datovým typem rowversion, aby se hodnoty automaticky generují v databázi. Zadání ale nemá ValueGeneratedOnAdd žádný vliv.

Poznámka

V závislosti na použitém poskytovateli databáze mohou být hodnoty generovány na straně klienta ef nebo v databázi. Pokud je hodnota vygenerována databází, může EF přiřadit dočasnou hodnotu, když přidáte entitu do kontextu. Tato dočasná hodnota se pak nahradí hodnotou vygenerovanou databází během SaveChanges(). Další informace najdete v dokumentu o dočasných hodnotách.

Generování hodnoty data a času

Běžným požadavkem je mít databázový sloupec, který obsahuje datum a čas prvního vložení sloupce (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, EF Core poskytovatelé obvykle nenastavují generování hodnot pro sloupce data a času automaticky – musíte to nakonfigurovat sami.

Časové razítko vytvoření

Konfigurace sloupce data a času tak, aby měl časové razítko vytvoření řádku, je obvykle otázkou konfigurace výchozí hodnoty s příslušnou SQL funkcí. Například na SQL Server 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()).

Aktualizace časového razítka

I když se uložené počítané sloupce zdají být dobrým řešením pro správu časových razítek poslední aktualizace, databáze obvykle GETDATE() neumožňují specifikovat funkce, jako je ve vypočítaných sloupcích. Alternativně můžete nastavit aktivační událost databáze, abyste dosáhli stejného efektu:

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

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

    DECLARE @Id INT

    SELECT @Id = INSERTED.BlogId
    FROM INSERTED

    UPDATE dbo.Blogs
    SET LastUpdated = GETDATE()
    WHERE BlogId = @Id
END

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

Přepsání generování hodnoty

I když je vlastnost nakonfigurovaná pro generování hodnot, v mnoha případech pro něj můžete stále explicitně zadat hodnotu. To, jestli to bude skutečně fungovat, závisí na konkrétním mechanismu generování hodnot, který je nakonfigurovaný. I když místo použití výchozí hodnoty sloupce můžete zadat explicitní hodnotu, u vypočítaných sloupců to stejné není možné.

Chcete-li přepsat generování hodnoty explicitní hodnotou, jednoduše nastavte vlastnost na libovolnou hodnotu, která není výchozí hodnotou CLR pro typ této vlastnosti (nullstringpro , 0 pro int, Guid.Empty pro Guidatd.).

Poznámka

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

Pokud chcete zadat explicitní hodnotu vlastností, 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);
}

Žádné generování hodnoty

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

V některých případech však můžete chtít zakázat generování hodnot, které bylo nastaveno podle konvence. Například primární klíč typu int je obvykle implicitně nakonfigurovaný jako value-generated-on-add (např. sloupec identity na SQL Server). Můžete to zakázat následujícím způsobem:

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

    public string Url { get; set; }
}