237

是否有“优雅”的方式为特定属性赋予默认值?

也许通过 DataAnnotations,类似于:

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

谢谢你。

4

17 回答 17

186

您可以通过手动编辑代码先迁移来做到这一点:

public override void Up()
{    
   AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true));
} 
于 2015-01-13T10:32:43.340 回答
91

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

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

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

我做了什么:

定义属性

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

在“OnModelCreating”的上下文中

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

在自定义 SqlGenerator

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

然后在 Migration Configuration 构造函数中,注册自定义 SQL 生成器。

SetSqlGenerator("System.Data.SqlClient", new CustomMigrationSqlGenerator());
于 2016-01-20T07:46:43.203 回答
90

上述答案确实有帮助,但只提供了部分解决方案。主要问题是,一旦您删除 Default value 属性,数据库中列的约束将不会被删除。所以以前的默认值仍将保留在数据库中。

这是该问题的完整解决方案,包括删除属性删除的 SQL 约束。我也在重新使用 .NET Framework 的 nativeDefaultValue属性。

用法

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

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

IdentityModels.cs 文件

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

配置.cs 文件

通过注册自定义 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;

    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)
    {
        if (column.Annotations.TryGetValue("SqlDefaultValue", out var 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 tableNameSplitByDot = tableName.Split('.');
        var tableSchema = tableNameSplitByDot[0];
        var tablePureName = tableNameSplitByDot[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++;
        return str;
    }
}
于 2016-06-29T14:13:03.580 回答
29

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

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 的回答显示了如何使用迁移、sql 或您的数据源使用的任何语言来完成。

于 2013-10-24T00:57:01.577 回答
14

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

注意:DefaultValue 属性不会自动设置你的属性值,你必须自己做

于 2014-05-14T14:14:28.087 回答
9

我承认我的方法逃避了整个“代码优先”的概念。但是,如果您能够仅更改表本身中的默认值...它比您必须在上面经历的长度要简单得多...我只是懒得做所有这些工作!

似乎海报的原始想法似乎可行:

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

我以为他们只是犯了添加引号的错误……但可惜没有这种直观性。其他建议对我来说太过分了(假设我拥有进入表格并进行更改所需的特权......并非每个开发人员都会在每种情况下)。最后,我只是按照老式的方式进行了操作。我在 SQL Server 表中设置了默认值……我的意思是真的,已经够了!注意:我进一步测试了添加迁移和更新数据库并且更改卡住了。 在此处输入图像描述

于 2017-09-26T22:43:11.390 回答
8

在@SedatKapanoglu 发表评论后,我添加了所有可行的方法,因为他是对的,只是使用流利的 API 是行不通的。

1- 创建自定义代码生成器并为 ColumnModel 覆盖 Generate。

   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);            
}
于 2017-01-27T18:39:09.027 回答
5

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

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

由此产生的迁移将是:

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

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

于 2018-12-24T16:40:10.043 回答
4

在 .NET Core 3.1 中,您可以在模型类中执行以下操作:

    public bool? Active { get; set; } 

在 DbContext OnModelCreating 中添加默认值。

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Foundation>()
            .Property(b => b.Active)
            .HasDefaultValueSql("1");

        base.OnModelCreating(modelBuilder);
    }

导致数据库中出现以下内容

在此处输入图像描述

注意:如果您的属性没有可为空(布尔?),您将收到以下警告

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'.
于 2020-05-25T19:01:53.020 回答
2
using System.ComponentModel;

[DefaultValue(true)]

public bool Active { get; set; }
于 2022-01-12T13:37:42.997 回答
1

在 2016 年 6 月 27 日发布的 EF 核心中,您可以使用 fluent API 设置默认值。转到 ApplicationDbContext 类,找到/创建方法名称 OnModelCreating 并添加以下流式 API。

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<YourTableName>()
        .Property(b => b.Active)
        .HasDefaultValue(true);
}
于 2019-12-29T12:55:37.770 回答
1

只需重载 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; }
    }

}
于 2017-04-13T08:26:15.030 回答
0

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

例如:

public class Thing {
    public bool IsBigThing{ get; set; } = false;
}
于 2017-04-10T09:45:03.657 回答
-1

Entity Framework Core Fluent API HasDefaultValue 方法用于指定映射到属性的数据库列的默认值。该值必须是一个常数。

public class Contact
{
    public int ContactId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public bool IsActive { get; set; }
    public DateTime DateCreated { get; set; }
}
public clas SampleContext : DbContext
{
    public DbSet<Contact> Contacts { get; set; }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Context>()
            .Propery(p => p.IsActive)
            .HasDefaultValue(true);
    }
}

或者

喜欢它!

您还可以指定用于计算默认值的 SQL 片段:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Created)
        .HasDefaultValueSql("getdate()");
}
于 2021-12-25T07:32:52.147 回答
-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");
}
于 2017-03-27T10:07:58.807 回答
-5

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

不过,您的里程可能首先因代码而异,但我没有使用过。

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

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

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

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

public Thingy()
{
  this.Iteration = 1;
于 2017-03-08T19:41:45.360 回答
-6

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

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

对于相同的财产。

于 2017-08-09T14:48:21.220 回答