entity-framework - entitytypeconfiguration - c# migrations default value



Entity Framework 6 Code first Valor padrão (9)

Existe uma maneira "elegante" de atribuir à propriedade específica um valor padrão?

Talvez por DataAnnotations, algo como:

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

Obrigado.


É simples! Apenas anote com necessário.

[Required]
public bool MyField { get; set; }

a migração resultante será:

migrationBuilder.AddColumn<bool>(
name: "MyField",
table: "MyTable",
nullable: false,
defaultValue: false);

Se você quiser true, altere o defaultValue para true na migração antes de atualizar o banco de dados


Admito que minha abordagem escapa à abordagem "Code First". Mas se você tem a capacidade de apenas alterar o valor padrão na própria tabela ... é muito mais simples do que os comprimentos que você tem que passar acima ... Eu sou muito preguiçoso para fazer todo esse trabalho!

Parece quase como se a idéia original dos pôsteres funcionasse:

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

Eu pensei que eles só cometeram o erro de adicionar citações ... mas não existe tal intuição. As outras sugestões foram demais para mim (desde que eu tenha os privilégios necessários para entrar na tabela e fazer as mudanças ... onde não é muito desenvolvedor em todas as situações). No final, fiz o mesmo à moda antiga. Eu defino o valor padrão na tabela do SQL Server ... Quero dizer realmente, já chega! OBSERVAÇÃO: Eu testei ainda mais a adição de uma migração e atualização do banco de dados e as alterações emperradas.


Apenas Sobrecarregue o construtor padrão da classe Model e passe qualquer parâmetro relevante que você possa ou não usar. Com isso, você pode fornecer facilmente valores padrão para atributos. Abaixo está um exemplo.

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; }
    }

}

As respostas acima ajudaram muito, mas apenas entregaram parte da solução. A principal questão é que, assim que você remover o atributo de valor Padrão, a restrição na coluna no banco de dados não será removida. Assim, o valor padrão anterior ainda permanecerá no banco de dados.

Aqui está uma solução completa para o problema, incluindo a remoção de restrições SQL na remoção de atributos. Também estou reutilizando o atributo DefaultValue nativo do .NET Framework.

Uso

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

Para que isso funcione, você precisa atualizar os arquivos IdentityModels.cs e Configuration.cs

Arquivo IdentityModels.cs

Adicionar / atualizar este método na sua classe 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);
}

Arquivo Configuration.cs

Atualize seu construtor da classe Configuration registrando o gerador Sql customizado, desta forma:

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

Em seguida, adicione a classe de gerador Sql personalizada (você pode adicioná-la ao arquivo Configuration.cs ou a um arquivo 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 = [email protected]"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;
    }
}

Descobri que apenas o uso do Auto-Property Initializer na propriedade da entidade é suficiente para realizar o trabalho.

Por exemplo:

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

Hmm ... Eu faço o DB primeiro e, nesse caso, isso é muito mais fácil. EF6 certo? Basta abrir o modelo, clicar com o botão direito do mouse na coluna para a qual você deseja definir um padrão, escolher propriedades e você verá um campo "DefaultValue". Apenas preencha e salve. Ele irá configurar o código para você.

Sua milhagem pode variar no código primeiro, embora eu não tenha trabalhado com isso.

O problema com muitas outras soluções é que, embora possam funcionar inicialmente, assim que você reconstruir o modelo, ele descartará qualquer código customizado inserido no arquivo gerado por máquina.

Este método funciona adicionando uma propriedade extra ao arquivo edmx:

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

E adicionando o código necessário ao construtor:

public Thingy()
{
  this.Iteration = 1;

O que eu fiz, eu inicializei os valores no construtor da entidade

Observação: os atributos DefaultValue não definem os valores de suas propriedades automaticamente. Você precisa fazer isso sozinho


Suas propriedades de modelo não precisam ser 'auto properties' Mesmo que isso seja mais fácil. E o atributo DefaultValue é realmente apenas metadados informativos. A resposta aceita here é uma alternativa à abordagem do construtor.

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; }        
}

Isso funcionará apenas para aplicativos que criam e consomem dados usando essa classe específica. Geralmente, isso não é um problema se o código de acesso a dados estiver centralizado. Para atualizar o valor em todos os aplicativos, você precisa configurar a fonte de dados para definir um valor padrão. A resposta de Devi mostra como isso pode ser feito usando migrações, sql ou qualquer idioma que sua fonte de dados fale.


Você pode fazer isso editando manualmente a primeira migração do código:

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




default-value