existe uma maneira "elegante" de atribuir um valor padrão a uma propriedade específica?
Talvez por DataAnnotations, algo como:
[DefaultValue("true")]
public bool Active { get; set; }
Obrigado.
public bool Inactive { get; set; }
J
existe uma maneira "elegante" de atribuir um valor padrão a uma propriedade específica?
Talvez por DataAnnotations, algo como:
[DefaultValue("true")]
public bool Active { get; set; }
Obrigado.
public bool Inactive { get; set; }
J
Respostas:
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));
}
Active
ao true
criar um Event
objeto. O valor padrão sempre está false
em uma propriedade bool não anulável; portanto, a menos que seja alterado, é isso que a estrutura da entidade salvará no banco de dados. Ou eu estou esquecendo de alguma coisa?
Já faz um tempo, mas deixando um recado para os outros. Consegui o que é necessário com um atributo e decorei meus campos de classe de modelo com esse atributo, conforme desejado.
[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }
Obtenha a ajuda destes 2 artigos:
O que eu fiz:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class SqlDefaultValueAttribute : Attribute
{
public string DefaultValue { get; set; }
}
modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));
private void SetAnnotatedColumn(ColumnModel col)
{
AnnotationValues values;
if (col.Annotations.TryGetValue("SqlDefaultValue", out values))
{
col.DefaultValueSql = (string)values.NewValue;
}
}
Em seguida, no construtor Migration Configuration, registre o gerador SQL personalizado.
SetSqlGenerator("System.Data.SqlClient", new CustomMigrationSqlGenerator());
[SqlDefaultValue(DefaultValue = "getutcdate()")]
todas as entidades. 1) Simplesmente remova modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));
2) AddmodelBuilder.Properties().Where(x => x.PropertyType == typeof(DateTime)).Configure(c => c.HasColumnType("datetime2").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed).HasColumnAnnotation("SqlDefaultValue", "getdate()"));
As respostas acima realmente ajudaram, mas apenas forneceram parte da solução. O principal problema é que, assim que você remover o atributo Valor padrão, a restrição na coluna no banco de dados não será removida. Portanto, 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 DefaultValue
atributo nativo do .NET Framework .
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[DefaultValue("getutcdate()")]
public DateTime CreatedOn { get; set; }
Para que isso funcione, é necessário atualizar os arquivos IdentityModels.cs e Configuration.cs
Adicione / atualize este método em sua ApplicationDbContext
classe
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);
}
Atualize seu Configuration
construtor de classe registrando o gerador Sql personalizado, 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á-lo 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 = $@"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;
}
}
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
atributo? Se sim, por quê? Nos meus testes, parecia não ter efeito deixar de fora.
As propriedades do seu modelo não precisam ser 'propriedades automáticas', embora isso seja mais fácil. E o atributo DefaultValue é realmente apenas metadados informativos. A resposta aceita aqui é 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. Normalmente, 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 da Devi mostra como isso pode ser feito usando migrações, sql ou qualquer idioma que sua fonte de dados fale.
O que eu fiz, eu inicializei valores no construtor da entidade
Nota: Os atributos DefaultValue não definirão os valores de suas propriedades automaticamente, você deve fazer isso sozinho
Após o comentário do @SedatKapanoglu, estou adicionando toda a minha abordagem que funciona, porque ele estava certo, apenas o uso da API fluente não funciona.
1- Crie um gerador de código personalizado e substitua Gerar para um 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- Atribua o novo gerador de código:
public sealed class Configuration : DbMigrationsConfiguration<Data.Context.EfSqlDbContext>
{
public Configuration()
{
CodeGenerator = new ExtendedMigrationCodeGenerator();
AutomaticMigrationsEnabled = false;
}
}
3- Use API fluente para criar a anotação:
public static void Configure(DbModelBuilder builder){
builder.Entity<Company>().Property(c => c.Status).HasColumnAnnotation("Default", 0);
}
É simples! Apenas anote com o 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
true
?
Admito que minha abordagem escapa a todo o conceito "Code First". Mas se você tem a capacidade de alterar apenas o valor padrão na própria tabela ... é muito mais simples do que os comprimentos que você precisa passar acima ... Estou com preguiça de fazer todo esse trabalho!
Quase parece que a ideia original dos pôsteres funcionaria:
[DefaultValue(true)]
public bool IsAdmin { get; set; }
Eu pensei que eles apenas cometeram o erro de adicionar aspas ... mas, infelizmente, não existe essa intuição. As outras sugestões foram demais para mim (desde que eu tenha os privilégios necessários para entrar na mesa e fazer as alterações ... onde nem todos os desenvolvedores estarão em todas as situações). No final, eu fiz da maneira antiga. Defino o valor padrão na tabela do SQL Server ... quero dizer, já chega! NOTA: Além disso, testei a adição de um banco de dados de migração e atualização e as alterações travadas.
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 facilmente fornecer 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; }
}
}
Vamos considerar que você tem um nome de classe chamado Produtos e um campo IsActive. você só precisa de um construtor create:
Public class Products
{
public Products()
{
IsActive = true;
}
public string Field1 { get; set; }
public string Field2 { get; set; }
public bool IsActive { get; set; }
}
Em seguida, seu valor padrão IsActive é True!
Edite :
se você quiser fazer isso com o SQL, use este comando:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.IsActive)
.HasDefaultValueSql("true");
}
No núcleo da EF lançado em 27 de junho de 2016, você pode usar a API fluente para definir o valor padrão. Vá para a classe ApplicationDbContext, encontre / crie o nome do método OnModelCreating e adicione a seguinte API fluente.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<YourTableName>()
.Property(b => b.Active)
.HasDefaultValue(true);
}
No .NET Core 3.1, você pode fazer o seguinte na classe de modelo:
public bool? Active { get; set; }
No DbContext OnModelCreating, você adiciona o valor padrão.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Foundation>()
.Property(b => b.Active)
.HasDefaultValueSql("1");
base.OnModelCreating(modelBuilder);
}
Resultando no seguinte no banco de dados
Nota: Se você não tiver nulo (bool?) Para sua propriedade, receberá o seguinte aviso
The 'bool' property 'Active' on entity type 'Foundation' is configured with a database-generated default. This default will always be used for inserts when the property has the value 'false', since this is the CLR default for the 'bool' type. Consider using the nullable 'bool?' type instead so that the default will only be used for inserts when the property value is 'null'.
Descobri que apenas o uso do Inicializador automático de propriedades na propriedade da entidade é suficiente para realizar o trabalho.
Por exemplo:
public class Thing {
public bool IsBigThing{ get; set; } = false;
}
Hmm ... eu faço DB primeiro, e nesse caso, isso é realmente 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". Basta preencher e salvar. Ele irá configurar o código para você.
Sua milhagem pode variar primeiro no código, mas não trabalhei com isso.
O problema com muitas outras soluções é que, embora possam funcionar inicialmente, assim que você reconstruir o modelo, ele lançará qualquer código personalizado inserido no arquivo gerado pela 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;
Defina o valor padrão para a coluna na tabela no MSSQL Server e, no código da classe, adicione o atributo, assim:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
para a mesma propriedade.
this.Active = true;
? Eu acho que o valor do banco de dados terá precedência ao buscar, mas tome cuidado se for necessário anexar uma entidade para uma atualização sem uma busca primeiro, pois o rastreamento de alterações pode ver isso como você deseja atualizar o valor. Comente porque não uso a EF há muito tempo e sinto que isso é um tiro no escuro.