Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
As colunas de banco de dados podem ter seus valores gerados de várias maneiras: colunas de chave primária são frequentemente inteiros de incremento automático, 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 o 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:
modelBuilder.Entity<Blog>()
.Property(b => b.Rating)
.HasDefaultValue(3);
Você também pode especificar um fragmento SQL usado para calcular o valor padrão:
modelBuilder.Entity<Blog>()
.Property(b => b.Created)
.HasDefaultValueSql("getdate()");
A partir do EF 10, para o SQL Server, você pode especificar explicitamente o nome para restrições de valor padrão, dando-lhe mais controle sobre seu esquema de banco de dados.
modelBuilder.Entity<Blog>()
.Property(b => b.Rating)
.HasDefaultValue(3, "DF_Blog_IsActive");
modelBuilder.Entity<Blog>()
.Property(b => b.Created)
.HasDefaultValueSql("getdate()" , "DF_Blog_IsActive");
Você também pode chamar UseNamedDefaultConstraints
para habilitar a nomenclatura automática de todas as restrições padrão. Observe que, se você tiver migrações existentes, a próxima migração adicionada renomeará cada restrição padrão em seu modelo.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.UseNamedDefaultConstraints();
}
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]");
A instrução acima cria uma coluna calculada virtual, cujo valor é calculado toda vez que é buscado do banco de dados. Você também pode especificar que uma coluna computada seja armazenada (às vezes chamada de persistida), o que significa que ela é computada em cada atualização da linha e é armazenada em disco junto com colunas regulares:
modelBuilder.Entity<Person>()
.Property(p => p.NameLength)
.HasComputedColumnSql("LEN([LastName]) + LEN([FirstName])", stored: true);
Chaves primárias
Por convenção, chaves primárias não compostas do tipo short, 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 no SQL Server é configurada automaticamente para ser uma coluna IDENTITY.
Para obter mais informações, consulte a documentação sobre chaves e diretrizes para estratégias de mapeamento de herança específicas.
Configurando explicitamente a geração de valor
Vimos acima que o EF Core configura automaticamente a geração de valor para chaves primárias, mas talvez queiramos fazer o mesmo para propriedades não chave. Você pode configurar qualquer propriedade para ter seu valor 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 na adição ou atualização:
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime LastUpdated { get; set; }
}
Ao contrário de valores padrão ou colunas computadas, não estamos especificando como os valores devem ser gerados; que depende do provedor de banco de dados que está sendo usado. Os provedores de banco de dados podem configurar automaticamente a geração de valor para alguns tipos de propriedade, mas outros podem exigir que você configure manualmente como o valor é gerado.
Por exemplo, no SQL Server, quando uma propriedade GUID é configurada como uma chave primária, o provedor executa automaticamente a geração de valor no lado do cliente, usando um algoritmo para gerar valores GUID sequenciais ótimos. No entanto, especificar ValueGeneratedOnAdd em uma propriedade DateTime não terá efeito (consulte a seção abaixo para geração de valor DateTime).
Da mesma forma, as propriedades byte[] configuradas como geradas durante a adição ou atualização e marcadas como tokens de simultaneidade são definidas com o tipo de dado rowversion, para que os valores sejam gerados automaticamente no banco de dados. No entanto, especificar ValueGeneratedOnAdd não tem efeito.
Consulte a documentação do provedor para obter as técnicas específicas de geração de valor compatíveis. A documentação de geração de valor do SQL Server pode ser encontrada aqui.
Geração de valor de data/hora
Uma solicitação comum é ter uma coluna de banco de dados que contenha a data/hora de quando a linha foi inserida pela primeira vez (valor gerado na adição) ou para quando ela foi atualizada pela última vez (valor gerado na adição ou atualização). Como há várias estratégias para fazer isso, os provedores do EF Core geralmente não configuram a geração de valor automaticamente para colunas de data/hora. Você mesmo precisa configurar isso.
Carimbo de data e hora da criação
Configurar uma coluna de data/hora para ter o timestamp de criação da linha geralmente é uma questão de definir um valor padrão com a função SQL apropriada. Por exemplo, no SQL Server, você pode usar o seguinte:
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 pela última vez, os bancos de dados geralmente não permitem especificar 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;
UPDATE B
SET LastUpdated = GETDATE()
FROM dbo.Blogs AS B
INNER JOIN INSERTED AS I
ON B.BlogId = I.BlogId
END
Para obter informações sobre como criar gatilhos, consulte a documentação sobre como usar o SQL bruto em migrações.
Sobrescrevendo 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 funcionará de fato depende do mecanismo de geração de valor específico que foi 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 com um valor explícito, basta definir a propriedade como qualquer valor que não seja o valor padrão CLR para o tipo dessa propriedade (null
para string
, 0
para int
, Guid.Empty
para , para Guid
, etc.).
Observação
A tentativa de inserir valores explícitos no SQL Server IDENTITY falha por padrão; consulte esses documentos para obter uma solução alternativa.
Para fornecer um valor explícito para propriedades que foram configuradas como valor gerado na adição ou atualização, 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);
}
Sem 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 que elas sejam 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-na-adição (por exemplo, uma coluna de identidade no 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; }
}