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

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

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

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

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

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

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

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

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

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

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 можно использовать следующее:

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

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

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

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

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

Сведения о создании триггеров см. в документации по использованию необработанного 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; }
}