是否有“优雅”的方式为特定属性提供默认值?
可能是通过DataAnnotations,例如:
[DefaultValue("true")]
public bool Active { get; set; }
谢谢。
答案 0 :(得分:146)
您可以通过手动编辑代码首次迁移来实现:
public override void Up()
{
AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true));
}
答案 1 :(得分:62)
已经有一段时间了,但给其他人留了一张便条。 我实现了属性所需的功能,并根据需要使用该属性修饰了我的模型类字段。
[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }
得到了这两篇文章的帮助:
我做了什么:
[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;
}
}
然后在Migration Configuration构造函数中,注册自定义SQL生成器。
SetSqlGenerator("System.Data.SqlClient", new HarmonyMigrationSqlGenerator());
答案 2 :(得分:58)
上述答案确实有所帮助,但只提供了部分解决方案。 主要问题是,只要删除“默认值”属性,就不会删除数据库中列的约束。因此,之前的默认值仍将保留在数据库中。
以下是该问题的完整解决方案,包括删除属性删除方面的SQL约束。
我也在重用.NET Framework的原生DefaultValue
属性。
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[DefaultValue("getutcdate()")]
public DateTime CreatedOn { get; set; }
为此,您需要更新 IdentityModels.cs 和 Configuration.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);
}
通过注册自定义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;
}
}
答案 3 :(得分:24)
您的模型属性不必是“自动属性”即使这更容易。 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; }
}
}
VS
public class Track
{
public Track()
{
LengthInMeters = 400;
}
public int LengthInMeters { get; set; }
}
这仅适用于使用此特定类创建和使用数据的应用程序。如果数据访问代码是集中的,通常这不是问题。要更新所有应用程序的值,您需要配置数据源以设置默认值。 Devi's answer显示了如何使用迁移,sql或您的数据源所说的任何语言来完成它。
答案 4 :(得分:10)
我做了什么,我在实体的构造函数中初始化了值
注意:DefaultValue属性不会自动设置属性的值,您必须自己设置
答案 5 :(得分:6)
在@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);
}
答案 6 :(得分:3)
我承认我的方法逃避了整个“Code First”方法。但是,如果你能够只更改表格中的默认值......它比你必须经历的长度简单得多......我只是懒得做所有这些工作!
看起来好像海报原创的想法会起作用:
[DefaultValue(true)]
public bool IsAdmin { get; set; }
我认为他们只是犯了添加引号的错误......但是没有这么直观。其他建议对我来说太过分了(授予我进入表格并进行更改所需的权限......在任何情况下,开发人员都不会这样做)。最后我只是用老式的方式做到了。我在SQL Server表中设置了默认值...我的意思是,已经足够了! 注意:我进一步测试了添加迁移和更新数据库,并且更改仍然存在。
答案 7 :(得分:2)
很简单!只需加上必填项即可。
[Required]
public bool MyField { get; set; }
最终的迁移将是:
migrationBuilder.AddColumn<bool>(
name: "MyField",
table: "MyTable",
nullable: false,
defaultValue: false);
如果要设置为true,请在迁移之前将defaultValue更改为true,然后再更新数据库
答案 8 :(得分: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; }
}
}
答案 9 :(得分:1)
在.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'.
答案 10 :(得分:0)
在2016年6月27日发布的EF core中,您可以使用fluent API设置默认值。转到ApplicationDbContext类,找到/创建方法名称OnModelCreating并添加以下流利的API。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<YourTableName>()
.Property(b => b.Active)
.HasDefaultValue(true);
}
答案 11 :(得分:-3)
让我们考虑您有一个名为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!
Edite :
如果您想使用SQL执行此操作,请使用以下命令:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.Property(b => b.IsActive)
.HasDefaultValueSql("true");
}
答案 12 :(得分:-3)
我发现只在实体属性上使用Auto-Property Initializer就足以完成工作。
例如:
public class Thing {
public bool IsBigThing{ get; set; } = false;
}
答案 13 :(得分:-4)
嗯......我先做数据库,在这种情况下,这实际上要容易得多。 EF6对吗?只需打开模型,右键单击要为其设置默认值的列,选择属性,您将看到“DefaultValue”字段。只需填写并保存即可。它会为你设置代码。
您的里程可能因代码优先而有所不同,我没有使用过。
许多其他解决方案的问题在于,虽然它们可能最初工作,但只要重建模型,它就会抛出您插入到机器生成的文件中的任何自定义代码。
此方法的工作原理是向edmx文件添加一个额外的属性:
<EntityType Name="Thingy">
<Property Name="Iteration" Type="Int32" Nullable="false" **DefaultValue="1"** />
通过向构造函数添加必要的代码:
public Thingy()
{
this.Iteration = 1;
答案 14 :(得分:-4)
在MSSQL Server的表中设置列的默认值,在类代码中添加属性,如下所示:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
为同一财产。