实体框架6代码第一个默认值

问题描述 投票:170回答:13

是否有“优雅”的方式给特定属性一个默认值?

也许通过DataAnnotations,类似于:

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

谢谢。

entity-framework ef-code-first default-value
13个回答
153
投票

您可以通过手动编辑代码首次迁移来实现:

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

-2
投票

让我们考虑您有一个名为Products的类名,并且您有一个IsActive字段。只需要一个创建构造函数:

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

然后您的IsActive默认值为True!

编辑:

如果要使用SQL执行此操作,请使用以下命令:

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

-3
投票

我发现只在实体属性上使用Auto-Property Initializer就足以完成工作。

例如:

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

-4
投票

嗯......我先做数据库,在这种情况下,这实际上要容易得多。 EF6对吗?只需打开模型,右键单击要为其设置默认值的列,选择属性,您将看到“DefaultValue”字段。只需填写并保存即可。它会为您设置代码。

您的里程可能因代码优先而有所不同,我没有使用过。

许多其他解决方案的问题在于,虽然它们可能最初工作,但只要重建模型,它就会抛出您插入到机器生成的文件中的任何自定义代码。

此方法通过向edmx文件添加额外属性来工作:

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

并通过向构造函数添加必要的代码:

public Thingy()
{
  this.Iteration = 1;

-4
投票

在MSSQL Server的表中设置列的默认值,在类代码中添加属性,如下所示:

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

对于同一财产。


64
投票

已经有一段时间了,但给其他人留了一张便条。我实现了属性所需的功能,并根据需要使用该属性修饰了我的模型类字段。

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

得到了这两篇文章的帮助:

我做了什么:

Define Attribute

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

In the "OnModelCreating" of the context

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

In the custom SqlGenerator

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

然后在迁移配置构造函数中,注册自定义SQL生成器。

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

61
投票

上述答案确实有所帮助,但只提供了部分解决方案。主要问题是,只要删除“默认值”属性,就不会删除数据库中列的约束。因此,之前的默认值仍将保留在数据库中。

以下是该问题的完整解决方案,包括删除属性删除时的SQL约束。我也在重用.NET Framework的原生DefaultValue属性。

Usage

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

为此,您需要更新IdentityModels.cs和Configuration.cs文件

IdentityModels.cs file

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

Configuration.cs file

通过注册自定义Sql生成器更新您的Configuration类构造函数,如下所示:

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

接下来,添加自定义Sql生成器类(您可以将其添加到Configuration.cs文件或单独的文件)

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

25
投票

您的模型属性不必是“自动属性”即使这更容易。 DefaultValue属性实际上只是提供信息的元数据接受的答案here是构造函数方法的一种替代方法。

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

public class Track
{
    public Track()
    {
        LengthInMeters = 400;   
    }

    public int LengthInMeters { get; set; }        
}

这仅适用于使用此特定类创建和使用数据的应用程序。如果数据访问代码是集中的,通常这不是问题。要更新所有应用程序的值,您需要配置数据源以设置默认值。 Devi's answer展示了如何使用迁移,sql或您的数据源所说的任何语言来完成它。


11
投票

我做了什么,我在实体的构造函数中初始化了值

注意:DefaultValue属性不会自动设置属性的值,您必须自己完成


7
投票

在@SedatKapanoglu评论之后,我添加了我的所有方法,因为他是对的,只是使用流畅的API不起作用。

1-创建自定义代码生成器并覆盖为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-分配新代码生成器:

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

3-使用流畅的api创建注释:

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

3
投票

我承认我的方法逃脱了整个“Code First”方法。但是,如果你能够只更改表格中的默认值......它比你必须经历的长度简单得多......我只是懒得做所有这些工作!

看起来好像海报原创的想法会起作用:

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

我以为他们只是犯了添加引号的错误......但是没有这么直观。其他建议对我来说太过分了(授予我进入表格并进行更改所需的权限......在任何情况下,开发人员都不会这样做)。最后我只是用老式的方式做到了。我在SQL Server表中设置了默认值...我的意思是,已经足够了!注意:我进一步测试了添加迁移和更新数据库并且更改卡住了。 enter image description here


2
投票

这很简单!只需要注释即可。

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

由此产生的迁移将是:

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

如果您需要true,请在更新数据库之前在迁移中将defaultValue更改为true


1
投票

Just Overload Model类的默认构造函数,并传递您可能使用或不使用的任何相关参数。通过这种方式,您可以轻松提供属性的默认值。以下是一个例子。

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

}
© www.soinside.com 2019 - 2024. All rights reserved.