Valores gerados

As colunas de banco de dados podem ter seus valores gerados de várias maneiras: as colunas de chave primária costumam incrementar automaticamente inteiros, outras colunas têm valores padrão ou computados, etc. Esta página detalha vários padrões de geração de valor de configuração com EF Core.

Valores padrão

Em bancos de dados relacionais, uma coluna pode ser configurada com um valor padrão; se uma linha for inserida sem um valor para essa coluna, o valor padrão será usado.

Você pode configurar um valor padrão em uma propriedade:

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

você também pode especificar um fragmento de SQL que é usado para calcular o valor padrão:

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

Colunas computadas

Na maioria dos bancos de dados relacionais, uma coluna pode ser configurada para ter seu valor computado no banco de dados, normalmente com uma expressão referindo-se a outras colunas:

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

O acima cria uma coluna computada virtual , cujo valor é computado toda vez que é buscado do banco de dados. Você também pode especificar que uma coluna computada seja armazenada (às vezes chamada de persistente), o que significa que ela é computada em todas as atualizações da linha e é armazenada em disco juntamente com as colunas regulares:

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

Observação

O suporte para a criação de colunas computadas armazenadas foi adicionado no EF Core 5,0.

Chaves primárias

Por convenção, chaves primárias não compostas do tipo curto, int, Long ou GUID são configuradas para ter valores gerados para entidades inseridas se um valor não for fornecido pelo aplicativo. Seu provedor de banco de dados normalmente cuida da configuração necessária; por exemplo, uma chave primária numérica em SQL Server é automaticamente configurada para ser uma coluna de identidade.

Para obter mais informações, consulte a documentação sobre chaves.

Configurando explicitamente a geração de valor

Vimos acima que EF Core automaticamente configura a geração de valores para chaves primárias, mas talvez queiramos fazer o mesmo para propriedades não chave. Você pode configurar qualquer propriedade para que seu valor seja gerado para entidades inseridas da seguinte maneira:

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

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

Da mesma forma, uma propriedade pode ser configurada para ter seu valor gerado em Adicionar ou atualizar:

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

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

Aviso

Ao contrário de valores padrão ou colunas computadas, não estamos especificando como os valores devem ser gerados; Isso depende do provedor de banco de dados que está sendo usado. Os provedores de banco de dados podem configurar automaticamente a geração de valores para alguns tipos de propriedade, mas outros podem exigir que você configure manualmente como o valor é gerado.

por exemplo, em SQL Server, quando uma propriedade GUID é configurada como um valor gerado em add, o provedor executa automaticamente a geração de valor do lado do cliente, usando um algoritmo para gerar valores de GUID sequenciais ideais. No entanto, especificar ValueGeneratedOnAdd em uma propriedade DateTime não terá nenhum efeito (ValueGeneratedOnAdd).

Da mesma forma, as propriedades byte [] configuradas como geradas em Adicionar ou atualizar e marcadas como tokens de simultaneidade são configuradas com o tipo de dados de série, para que os valores sejam gerados automaticamente no banco de dado. No entanto, a especificação ValueGeneratedOnAdd não tem nenhum efeito.

Observação

Dependendo do provedor de banco de dados que está sendo usado, os valores podem ser gerados no lado do cliente pelo EF ou no banco de dados. Se o valor for gerado pelo banco de dados, o EF poderá atribuir um valor temporário quando você adicionar a entidade ao contexto; Esse valor temporário será então substituído pelo valor gerado pelo banco de dados durante SaveChanges() . Para obter mais informações, consulte documentos sobre valores temporários.

Geração de valor de data/hora

Uma solicitação comum é ter uma coluna de banco de dados que contém a data/hora de quando a coluna foi inserida pela primeira vez (valor gerado em Add) ou para quando foi a última atualização (valor gerado em Add ou Update). Como há várias estratégias para fazer isso, os provedores de EF Core geralmente não configuram a geração de valores automaticamente para colunas de data/hora – você precisa configurar isso por conta própria.

Timestamp de criação

a configuração de uma coluna de data/hora para ter o carimbo de hora de criação da linha geralmente é uma questão de configurar um valor padrão com a função de SQL apropriada. por exemplo, em SQL Server você pode usar o seguinte:

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

Certifique-se de selecionar a função apropriada, pois várias podem existir (por exemplo, GETDATE() vs. GETUTCDATE() ).

Atualizar carimbo de data/hora

Embora as colunas computadas armazenadas pareçam uma boa solução para gerenciar carimbos de data/hora atualizados, os bancos de dados geralmente não permitem a especificação de funções como GETDATE() em uma coluna computada. Como alternativa, você pode configurar um gatilho de banco de dados para obter o mesmo efeito:

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

para obter informações sobre a criação de gatilhos, consulte a documentação sobre como usar SQL bruta em migrações.

Substituindo a geração de valor

Embora uma propriedade esteja configurada para geração de valor, em muitos casos, você ainda pode especificar explicitamente um valor para ela. Se isso realmente funcionará dependendo do mecanismo de geração de valor específico configurado; Embora você possa especificar um valor explícito em vez de usar o valor padrão de uma coluna, o mesmo não pode ser feito com colunas computadas.

Para substituir a geração de valor por um valor explícito, basta definir a propriedade como qualquer valor que não seja o valor padrão do CLR para o tipo dessa propriedade (para, para, nullstring para, 0intGuid.EmptyGuid etc.).

Observação

a tentativa de inserir valores explícitos em SQL Server identidade falha por padrão; consulte estes documentos para obter uma solução alternativa.

Para fornecer um valor explícito para propriedades que foram configuradas como valor gerado em Adicionar ou atualizar, você também deve configurar a propriedade da seguinte maneira:

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

Nenhuma geração de valor

Além de cenários específicos, como os descritos acima, as propriedades normalmente não têm nenhuma geração de valor configurada; Isso significa que cabe ao aplicativo sempre fornecer um valor a ser salvo no banco de dados. Esse valor deve ser atribuído a novas entidades antes de serem adicionadas ao contexto.

No entanto, em alguns casos, talvez você queira desabilitar a geração de valor que foi configurada por convenção. Por exemplo, uma chave primária do tipo int geralmente é configurada implicitamente como valor gerado-on-Add (por exemplo, coluna de identidade em SQL Server). Você pode desabilitar isso por meio do seguinte:

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

    public string Url { get; set; }
}