framework first code entity-framework ef-code-first default-value

entity-framework - first - migration entity framework default value



Código de Entity Framework 6 first Valor predeterminado (12)

¿Existe una forma "elegante" de otorgar a un bien específico un valor predeterminado?

Tal vez por DataAnnotations, algo así como:

[DefaultValue("true")] public bool Active { get; set; }

Gracias.


¡No sé de dónde vienen estas respuestas!

Consideremos que tiene un nombre de clase llamado Productos y tiene un campo IsActive. solo necesitas crear un constructor:

Public class Products { public Products() { IsActive = true; } public string Field1 { get; set; } public string Field2 { get; set; } public bool IsActive { get; set; } }

¡Entonces su valor predeterminado de IsActive es Verdadero!

Edite :

si quieres hacer esto con SQL usa este comando:

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


Admito que mi enfoque escapa a todo el enfoque de "codificar primero". Pero si tienes la capacidad de simplemente cambiar el valor predeterminado en la tabla en sí ... es mucho más simple que las longitudes que tienes que pasar por encima ... ¡Soy demasiado flojo para hacer todo ese trabajo!

Casi parece que la idea original de los carteles funcionaría:

[DefaultValue(true)] public bool IsAdmin { get; set; }

Pensé que acababan de cometer el error de agregar citas ... pero no hay tal intuición. Las otras sugerencias fueron demasiado para mí (a condición de que tenga los privilegios necesarios para entrar en la mesa y hacer los cambios ... donde no habrá mucho desarrollador en cada situación). Al final solo lo hice a la vieja usanza. Configuré el valor predeterminado en la tabla de SQL Server ... ¡En serio, ya es suficiente! NOTA: Probé más haciendo una migración de adición y una base de datos de actualización y los cambios se atascaron.


Descubrí que solo usar el Inicializador de propiedades automáticas en la propiedad de la entidad es suficiente para realizar el trabajo.

Por ejemplo:

public class Thing { public bool IsBigThing{ get; set; } = false; }


Después del comentario de @SedatKapanoglu, agrego todo mi enfoque que funciona, porque tenía razón, solo que usar la API fluida no funciona.

1- Crea un generador de código personalizado y anula Generar para un ColumnModel.

public class ExtendedMigrationCodeGenerator : CSharpMigrationCodeGenerator { protected override void Generate(ColumnModel column, IndentedTextWriter writer, bool emitName = false) { if (column.Annotations.Keys.Contains("Default")) { var value = Convert.ChangeType(column.Annotations["Default"].NewValue, column.ClrDefaultValue.GetType()); column.DefaultValue = value; } base.Generate(column, writer, emitName); } }

2- Asignar el nuevo generador de código:

public sealed class Configuration : DbMigrationsConfiguration<Data.Context.EfSqlDbContext> { public Configuration() { CodeGenerator = new ExtendedMigrationCodeGenerator(); AutomaticMigrationsEnabled = false; } }

3- Utilice una API fluida para crear la Anotación:

public static void Configure(DbModelBuilder builder){ builder.Entity<Company>().Property(c => c.Status).HasColumnAnnotation("Default", 0); }


Establezca el valor predeterminado para la columna en la tabla en el servidor MSSQL, y en el atributo de agregar código de clase, así:

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

para la misma propiedad.


Ha pasado un tiempo, pero dejando una nota para los demás. Logré lo que se necesita con un atributo y decoré mis campos de clase de modelo con ese atributo como quisiera.

[SqlDefaultValue(DefaultValue = "getutcdate()")] public DateTime CreatedDateUtc { get; set; }

Obtuve la ayuda de estos 2 artículos:

Lo que hice:

Definir atributo

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class SqlDefaultValueAttribute : Attribute { public string DefaultValue { get; set; } }

En "OnModelCreating" del contexto

modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));

En el SqlGenerator personalizado

private void SetAnnotatedColumn(ColumnModel col) { AnnotationValues values; if (col.Annotations.TryGetValue("SqlDefaultValue", out values)) { col.DefaultValueSql = (string)values.NewValue; } }

Luego, en el constructor de configuración de migración, registre el generador de SQL personalizado.

SetSqlGenerator("System.Data.SqlClient", new HarmonyMigrationSqlGenerator());


Hmm ... Primero hago DB, y en ese caso, esto es mucho más fácil. EF6 ¿verdad? Simplemente abra su modelo, haga clic con el botón derecho en la columna para la que desea establecer un valor predeterminado, elija propiedades y verá el campo "DefaultValue". Solo completa eso y ahorra. Configurará el código para usted.

Sin embargo, su kilometraje puede variar en el código, no he trabajado con eso.

El problema con muchas otras soluciones es que si bien pueden funcionar inicialmente, tan pronto como reconstruya el modelo, arrojará cualquier código personalizado que haya insertado en el archivo generado por la máquina.

Este método funciona al agregar una propiedad adicional al archivo edmx:

<EntityType Name="Thingy"> <Property Name="Iteration" Type="Int32" Nullable="false" **DefaultValue="1"** />

Y agregando el código necesario al constructor:

public Thingy() { this.Iteration = 1;


Las propiedades de su modelo no tienen que ser ''propiedades automáticas'' Aunque eso es más fácil. Y el atributo DefaultValue es realmente solo metadatos informativos. La respuesta aceptada here es una alternativa al enfoque de constructor.

public class Track { private const int DEFAULT_LENGTH = 400; private int _length = DEFAULT_LENGTH; [DefaultValue(DEFAULT_LENGTH)] public int LengthInMeters { get { return _length; } set { _length = value; } } }

vs.

public class Track { public Track() { LengthInMeters = 400; } public int LengthInMeters { get; set; } }

Esto solo funcionará para las aplicaciones que crean y consumen datos usando esta clase específica. Por lo general, esto no es un problema si el código de acceso a datos está centralizado. Para actualizar el valor en todas las aplicaciones, necesita configurar el origen de datos para establecer un valor predeterminado. La respuesta de Devi muestra cómo se puede hacer usando migraciones, sql o cualquier idioma que hable su fuente de datos.


Las respuestas anteriores realmente ayudaron, pero solo entregaron parte de la solución. El problema principal es que tan pronto como elimine el atributo de valor predeterminado, la restricción en la columna en la base de datos no se eliminará. Por lo tanto, el valor predeterminado anterior permanecerá en la base de datos.

Aquí hay una solución completa al problema, incluida la eliminación de las restricciones SQL en la eliminación de atributos. También estoy reutilizando el atributo DefaultValue nativo de .NET Framework.

Uso

[DatabaseGenerated(DatabaseGeneratedOption.Computed)] [DefaultValue("getutcdate()")] public DateTime CreatedOn { get; set; }

Para que esto funcione, debe actualizar los archivos IdentityModels.cs y Configuration.cs

Archivo IdentityModels.cs

Agregue / actualice este método en su clase ApplicationDbContext

protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); var convention = new AttributeToColumnAnnotationConvention<DefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.SingleOrDefault().Value.ToString()); modelBuilder.Conventions.Add(convention); }

Archivo Configuration.cs

Actualice su constructor de clase de Configuration registrando un generador Sql personalizado, como este:

internal sealed class Configuration : DbMigrationsConfiguration<ApplicationDbContext> { public Configuration() { // DefaultValue Sql Generator SetSqlGenerator("System.Data.SqlClient", new DefaultValueSqlServerMigrationSqlGenerator()); } }

A continuación, agregue la clase de generador Sql personalizado (puede agregarlo al archivo Configuration.cs o a un archivo separado)

internal class DefaultValueSqlServerMigrationSqlGenerator : SqlServerMigrationSqlGenerator { private int dropConstraintCount = 0; protected override void Generate(AddColumnOperation addColumnOperation) { SetAnnotatedColumn(addColumnOperation.Column, addColumnOperation.Table); base.Generate(addColumnOperation); } protected override void Generate(AlterColumnOperation alterColumnOperation) { SetAnnotatedColumn(alterColumnOperation.Column, alterColumnOperation.Table); base.Generate(alterColumnOperation); } protected override void Generate(CreateTableOperation createTableOperation) { SetAnnotatedColumns(createTableOperation.Columns, createTableOperation.Name); base.Generate(createTableOperation); } protected override void Generate(AlterTableOperation alterTableOperation) { SetAnnotatedColumns(alterTableOperation.Columns, alterTableOperation.Name); base.Generate(alterTableOperation); } private void SetAnnotatedColumn(ColumnModel column, string tableName) { AnnotationValues values; if (column.Annotations.TryGetValue("SqlDefaultValue", out values)) { if (values.NewValue == null) { column.DefaultValueSql = null; using (var writer = Writer()) { // Drop Constraint writer.WriteLine(GetSqlDropConstraintQuery(tableName, column.Name)); Statement(writer); } } else { column.DefaultValueSql = (string)values.NewValue; } } } private void SetAnnotatedColumns(IEnumerable<ColumnModel> columns, string tableName) { foreach (var column in columns) { SetAnnotatedColumn(column, tableName); } } private string GetSqlDropConstraintQuery(string tableName, string columnName) { var tableNameSplittedByDot = tableName.Split(''.''); var tableSchema = tableNameSplittedByDot[0]; var tablePureName = tableNameSplittedByDot[1]; var str = $@"DECLARE @var{dropConstraintCount} nvarchar(128) SELECT @var{dropConstraintCount} = name FROM sys.default_constraints WHERE parent_object_id = object_id(N''{tableSchema}.[{tablePureName}]'') AND col_name(parent_object_id, parent_column_id) = ''{columnName}''; IF @var{dropConstraintCount} IS NOT NULL EXECUTE(''ALTER TABLE {tableSchema}.[{tablePureName}] DROP CONSTRAINT ['' + @var{dropConstraintCount} + '']'')"; dropConstraintCount = dropConstraintCount + 1; return str; } }


Lo que hice, inicié valores en el constructor de la entidad

Nota: los atributos DefaultValue no configurarán los valores de sus propiedades automáticamente, usted debe hacerlo usted mismo


Puede hacerlo editando manualmente la primera migración del código:

public override void Up() { AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true)); }


Simplemente sobrecarga el constructor predeterminado de la clase Model y pasa cualquier parámetro relevante que puedas o no puedas usar. De esta forma, puede proporcionar fácilmente valores predeterminados para los atributos. A continuación hay un ejemplo.

using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Aim.Data.Domain { [MetadataType(typeof(LoginModel))] public partial class Login { public Login(bool status) { this.CreatedDate = DateTime.Now; this.ModifiedDate = DateTime.Now; this.Culture = "EN-US"; this.IsDefaultPassword = status; this.IsActive = status; this.LoginLogs = new HashSet<LoginLog>(); this.LoginLogHistories = new HashSet<LoginLogHistory>(); } } public class LoginModel { [Key] [ScaffoldColumn(false)] public int Id { get; set; } [Required] public string LoginCode { get; set; } [Required] public string Password { get; set; } public string LastPassword { get; set; } public int UserGroupId { get; set; } public int FalseAttempt { get; set; } public bool IsLocked { get; set; } public int CreatedBy { get; set; } public System.DateTime CreatedDate { get; set; } public Nullable<int> ModifiedBy { get; set; } public Nullable<System.DateTime> ModifiedDate { get; set; } public string Culture { get; set; } public virtual ICollection<LoginLog> LoginLogs { get; set; } public virtual ICollection<LoginLogHistory> LoginLogHistories { get; set; } } }