Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Las columnas de base de datos pueden tener sus valores generados de varias maneras: las columnas de clave principal suelen incrementar automáticamente los enteros, otras columnas tienen valores predeterminados o calculados, etc. En esta página se detallan varios patrones para la generación de valores de configuración con EF Core.
Valores predeterminados
En las bases de datos relacionales, se puede configurar una columna con un valor predeterminado; si se inserta una fila sin un valor para esa columna, se usará el valor predeterminado.
Puede configurar un valor predeterminado en una propiedad:
modelBuilder.Entity<Blog>()
.Property(b => b.Rating)
.HasDefaultValue(3);
También puede especificar un fragmento de SQL que se usa para calcular el valor predeterminado:
modelBuilder.Entity<Blog>()
.Property(b => b.Created)
.HasDefaultValueSql("getdate()");
A partir de EF 10, para SQL Server puede especificar explícitamente el nombre de las restricciones de valor predeterminadas, lo que proporciona más control sobre el esquema de la base de datos.
modelBuilder.Entity<Blog>()
.Property(b => b.Rating)
.HasDefaultValue(3, "DF_Blog_IsActive");
modelBuilder.Entity<Blog>()
.Property(b => b.Created)
.HasDefaultValueSql("getdate()" , "DF_Blog_IsActive");
También puede llamar al UseNamedDefaultConstraints
para habilitar la nomenclatura automática de todas las restricciones predeterminadas. Tenga en cuenta que si tiene migraciones existentes, la siguiente migración que agregue cambiará el nombre de cada restricción predeterminada única en el modelo.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.UseNamedDefaultConstraints();
}
Columnas calculadas
En la mayoría de las bases de datos relacionales, se puede configurar una columna para que su valor se calcule en la base de datos, normalmente con una expresión que hace referencia a otras columnas:
modelBuilder.Entity<Person>()
.Property(p => p.DisplayName)
.HasComputedColumnSql("[LastName] + ', ' + [FirstName]");
Lo anterior crea una columna calculada virtual , cuyo valor se calcula cada vez que se captura de la base de datos. También puede especificar que se almacene una columna calculada (a veces denominada persistente), lo que significa que se calcula en cada actualización de la fila y se almacena en el disco junto con columnas normales:
modelBuilder.Entity<Person>()
.Property(p => p.NameLength)
.HasComputedColumnSql("LEN([LastName]) + LEN([FirstName])", stored: true);
Claves principales
Por convención, las claves principales no compuestas de tipo short, int, long o Guid están configuradas para tener valores generados para las entidades insertadas si la aplicación no proporciona ningún valor. El proveedor de bases de datos normalmente se encarga de la configuración necesaria; Por ejemplo, una clave principal numérica en SQL Server se configura automáticamente para que sea una columna IDENTITY.
Para obtener más información, consulte la documentación sobre claves e instrucciones para estrategias de asignación de herencia específicas.
Configuración explícita de la generación de valores
Hemos visto anteriormente que EF Core configura automáticamente la generación de valores para las claves principales, pero es posible que deseemos hacer lo mismo para las propiedades que no son de clave. Puede configurar cualquier propiedad para que tenga su valor generado para las entidades insertadas de la siguiente manera:
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime Inserted { get; set; }
}
Del mismo modo, se puede configurar una propiedad para que se genere su valor al agregar o actualizar:
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime LastUpdated { get; set; }
}
A diferencia de los valores predeterminados o las columnas calculadas, no se especifica cómo se van a generar los valores; que depende del proveedor de base de datos que se use. Los proveedores de bases de datos pueden configurar automáticamente la generación de valores para algunos tipos de propiedades, pero otros pueden requerir que configure manualmente cómo se genera el valor.
Por ejemplo, en SQL Server, cuando una propiedad GUID está configurada como clave principal, el proveedor realiza automáticamente el lado cliente de generación de valores mediante un algoritmo para generar valores guid secuenciales óptimos. Sin embargo, especificar ValueGeneratedOnAdd en una propiedad DateTime no tendrá ningún efecto (consulte la sección siguiente para la generación de valores DateTime).
Del mismo modo, las propiedades byte[] configuradas para generarse al añadir o actualizar y marcadas como tokens de concurrencia se establecen con el tipo de datos rowversion, de modo que los valores se generen automáticamente en la base de datos. Sin embargo, especificar ValueGeneratedOnAdd no tiene ningún efecto.
Consulte la documentación de su proveedor para conocer las técnicas específicas de generación de valores que admite. La documentación de generación de valores de SQL Server se puede encontrar aquí.
Generación de valores de fecha y hora
Una solicitud común es tener una columna de base de datos que contenga la fecha y hora para la que se insertó por primera vez la fila (valor generado en add) o cuando se actualizó por última vez (valor generado al agregar o actualizar). Como hay varias estrategias para hacerlo, los proveedores de EF Core normalmente no configuran automáticamente la generación de valores para las columnas de fecha y hora, tiene que configurar esto usted mismo.
Marca de tiempo de creación
La configuración de una columna de fecha y hora para tener la marca de tiempo de creación de la fila suele ser una cuestión de configurar un valor predeterminado con la función SQL adecuada. Por ejemplo, en SQL Server puede usar lo siguiente:
modelBuilder.Entity<Blog>()
.Property(b => b.Created)
.HasDefaultValueSql("getdate()");
Asegúrese de seleccionar la función adecuada, ya que pueden existir varias (por ejemplo, GETDATE()
frente a GETUTCDATE()
).
Actualizar marca de tiempo
Aunque las columnas calculadas almacenadas parecen una buena solución para administrar marcas de tiempo actualizadas por última vez, las bases de datos normalmente no permiten especificar funciones como GETDATE()
en una columna calculada. Como alternativa, puede configurar un desencadenador de base de datos para lograr el mismo efecto:
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 obtener información sobre cómo crear desencadenadores, consulte la documentación sobre el uso de SQL sin procesar en migraciones.
Anulación de la generación de valores
Aunque una propiedad está configurada para la generación de valores, en muchos casos puede especificar explícitamente un valor para ella. Si esto realmente funcionará depende del mecanismo de generación de valores específico que se ha configurado; aunque puede especificar un valor explícito en lugar de usar el valor predeterminado de una columna, no se puede hacer lo mismo con las columnas calculadas.
Para invalidar la generación de valores con un valor explícito, simplemente establezca la propiedad en cualquier valor que no sea el valor predeterminado clR para el tipo de esa propiedad (null
para string
, 0
para int
, Guid.Empty
para , etc Guid
.).
Nota:
Si se intenta insertar valores explícitos en SQL Server IDENTITY, se produce un error de forma predeterminada; consulte estos documentos para obtener una solución alternativa.
Para proporcionar un valor explícito para las propiedades que se han configurado como valor generado al agregar o actualizar, también debe configurar la propiedad de la siguiente manera:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().Property(b => b.LastUpdated)
.ValueGeneratedOnAddOrUpdate()
.Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save);
}
Sin generación de valores
Aparte de escenarios específicos, como los descritos anteriormente, las propiedades normalmente no tienen configurada la generación de valores; esto significa que la aplicación siempre debe proporcionar un valor que se va a guardar en la base de datos. Este valor se debe asignar a nuevas entidades antes de que se agreguen al contexto.
Sin embargo, en algunos casos puede que desee deshabilitar la generación de valores configurada por convención. Por ejemplo, una clave principal de tipo entero normalmente se configura implícitamente para generar valores al agregar (por ejemplo, como una columna de identidad en SQL Server). Puede deshabilitarlo a través de lo siguiente:
public class Blog
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int BlogId { get; set; }
public string Url { get; set; }
}