Поделиться через


Созданные значения

Столбцы базы данных могут создавать свои значения различными способами: столбцы первичного ключа часто являются автоматически добавочными целыми числами, другие столбцы имеют значения по умолчанию или вычисляемые значения и т. д. На этой странице описаны различные шаблоны создания значений конфигурации с помощью EF Core.

Значения по умолчанию

В реляционных базах данных столбец можно настроить со значением по умолчанию; Если строка вставляется без значения для этого столбца, будет использоваться значение по умолчанию.

Можно настроить значение по умолчанию для свойства:

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

Можно также указать фрагмент SQL, используемый для вычисления значения по умолчанию:

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

Начиная с EF 10, для SQL Server можно явно указать имя ограничений значений по умолчанию, что дает вам больше контроля над схемой базы данных.

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

Вы также можете вызвать UseNamedDefaultConstraints для включения автоматического именования всех ограничений по умолчанию. Обратите внимание, что если у вас есть существующие миграции, то следующая миграция переименует каждое ограничение по умолчанию в вашей модели.

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

Вычисляемые столбцы

В большинстве реляционных баз данных столбец можно настроить для вычисления значения в базе данных, как правило, с выражением, ссылающимся на другие столбцы:

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

В приведенном выше примере создается виртуальный вычисляемый столбец, значение которого вычисляется каждый раз, когда оно извлекается из базы данных. Кроме того, можно указать, что вычисляемый столбец хранится (иногда называется сохраненным), то есть вычисляется при каждом обновлении строки и хранится на диске вместе с обычными столбцами:

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

Первичные ключи

По соглашению, первичные ключи без составных типов, такие как short, int, long или Guid, настраиваются таким образом, чтобы значения автоматически генерировались для вставленных сущностей, если приложение не предоставляет значение. Поставщик базы данных обычно заботится о необходимой конфигурации; Например, числовой первичный ключ в SQL Server автоматически настраивается как столбец IDENTITY.

Дополнительные сведения см. в документации по ключам и рекомендациям по конкретным стратегиям сопоставления наследования.

Явная настройка генерации значений

Мы видели выше, что EF Core автоматически настраивает создание значений для первичных ключей, но мы можем сделать то же самое для свойств, отличных от ключей. Любое свойство можно настроить таким образом, чтобы его значение было создано для вставленных сущностей следующим образом:

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

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

Аналогичным образом можно настроить свойство, чтобы его значение было создано при добавлении или обновлении:

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

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

В отличие от значений по умолчанию или вычисляемых столбцов, мы не указываем способ создания значений; это зависит от используемого поставщика базы данных. Поставщики баз данных могут автоматически настроить создание значений для некоторых типов свойств, но другим пользователям может потребоваться вручную настроить создание значения.

Например, в SQL Server, когда свойство GUID настроено как первичный ключ, поставщик автоматически выполняет создание значений на стороне клиента с помощью алгоритма для создания оптимальных последовательных значений GUID. Однако указание ValueGeneratedOnAdd свойства DateTime не будет иметь никакого эффекта (см. раздел ниже для создания значений DateTime).

Аналогичным образом свойства byte[], настроенные как созданные при добавлении или обновлении и помеченные как маркеры параллелизма, настраиваются с типом данных rowversion, чтобы значения автоматически создавались в базе данных. Однако указание ValueGeneratedOnAdd не действует.

Ознакомьтесь с документацией поставщика по определенным методам создания значений, которые он поддерживает. Документацию по генерации значений в SQL Server можно найти здесь.

Создание значений даты и времени

Общий запрос — иметь столбец базы данных, содержащий дату и время первой вставки строки (значение, созданное при добавлении), или время последнего обновления (значение, созданное при добавлении или обновлении). Так как для этого существуют различные стратегии, поставщики EF Core обычно не настраивают автоматическое создание значений для столбцов даты и времени. Это необходимо настроить самостоятельно.

Метка времени создания

Настройка столбца даты и времени с меткой времени создания строки обычно сводится к настройке значения по умолчанию с использованием соответствующей функции SQL. Например, в SQL Server можно использовать следующее:

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

Не забудьте выбрать соответствующую функцию, так как может существовать несколько (например GETDATE() , vs. GETUTCDATE()).

Обновление метки времени

Хотя сохраненные вычисляемые столбцы кажутся хорошим решением для управления метками времени последнего обновления, базы данных обычно не позволяют указывать такие функции, как GETDATE() в вычисляемом столбце. В качестве альтернативы можно настроить триггер базы данных для достижения того же эффекта:

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

Сведения о создании триггеров см. в документации по использованию необработанных SQL в миграциях.

Переопределение генерации значений

Хотя свойство настроено для создания значений, во многих случаях можно явно указать для него значение. Будет ли это на самом деле работать, зависит от конкретного механизма генерации значений, который был настроен, хотя можно указать конкретное значение вместо использования значения по умолчанию столбца, то же самое нельзя сделать с вычисляемыми столбцами.

Чтобы заменить автоматическое создание значений на явное, просто задайте для свойства любое значение, которое не является значением по умолчанию CLR для типа этого свойства (null для string, 0 для int, Guid.Empty для Guid и т. д.).

Замечание

Попытка вставки явных значений в SQL Server IDENTITY завершается ошибкой по умолчанию; См. эти документы для обходного решения.

Чтобы указать явное значение для свойств, которые были настроены в качестве значения, созданного при добавлении или обновлении, необходимо также настроить свойство следующим образом:

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

Нет создания значений

Помимо определенных сценариев, таких как описанные выше, свойства обычно не имеют настроенного поколения значений; это означает, что приложение должно всегда предоставлять значение, которое нужно сохранить в базе данных. Это значение должно быть назначено новым сущностям, прежде чем они будут добавлены в контекст.

Однако в некоторых случаях может потребоваться отключить создание значений, которое было настроено по умолчанию. Например, первичный ключ типа int обычно неявно настраивается на генерацию значения при добавлении (например, столбец идентификаторов в SQL Server). Это можно отключить с помощью следующих действий:

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

    public string Url { get; set; }
}