是否有“优雅”的方式给特定属性一个默认值?
也许通过DataAnnotations,类似于:
[DefaultValue("true")]
public bool Active { get; set; }
谢谢。
您可以通过手动编辑代码首次迁移来实现:
public override void Up()
{
AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true));
}
让我们考虑您有一个名为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");
}
我发现只在实体属性上使用Auto-Property Initializer就足以完成工作。
例如:
public class Thing {
public bool IsBigThing{ get; set; } = false;
}
嗯......我先做数据库,在这种情况下,这实际上要容易得多。 EF6对吗?只需打开模型,右键单击要为其设置默认值的列,选择属性,您将看到“DefaultValue”字段。只需填写并保存即可。它会为您设置代码。
您的里程可能因代码优先而有所不同,我没有使用过。
许多其他解决方案的问题在于,虽然它们可能最初工作,但只要重建模型,它就会抛出您插入到机器生成的文件中的任何自定义代码。
此方法通过向edmx文件添加额外属性来工作:
<EntityType Name="Thingy">
<Property Name="Iteration" Type="Int32" Nullable="false" **DefaultValue="1"** />
并通过向构造函数添加必要的代码:
public Thingy()
{
this.Iteration = 1;
在MSSQL Server的表中设置列的默认值,在类代码中添加属性,如下所示:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
对于同一财产。
已经有一段时间了,但给其他人留了一张便条。我实现了属性所需的功能,并根据需要使用该属性修饰了我的模型类字段。
[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;
}
}
然后在迁移配置构造函数中,注册自定义SQL生成器。
SetSqlGenerator("System.Data.SqlClient", new HarmonyMigrationSqlGenerator());
上述答案确实有所帮助,但只提供了部分解决方案。主要问题是,只要删除“默认值”属性,就不会删除数据库中列的约束。因此,之前的默认值仍将保留在数据库中。
以下是该问题的完整解决方案,包括删除属性删除时的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;
}
}
您的模型属性不必是“自动属性”即使这更容易。 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或您的数据源所说的任何语言来完成它。
我做了什么,我在实体的构造函数中初始化了值
注意:DefaultValue属性不会自动设置属性的值,您必须自己完成
在@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);
}
我承认我的方法逃脱了整个“Code First”方法。但是,如果你能够只更改表格中的默认值......它比你必须经历的长度简单得多......我只是懒得做所有这些工作!
看起来好像海报原创的想法会起作用:
[DefaultValue(true)]
public bool IsAdmin { get; set; }
我以为他们只是犯了添加引号的错误......但是没有这么直观。其他建议对我来说太过分了(授予我进入表格并进行更改所需的权限......在任何情况下,开发人员都不会这样做)。最后我只是用老式的方式做到了。我在SQL Server表中设置了默认值...我的意思是,已经足够了!注意:我进一步测试了添加迁移和更新数据库并且更改卡住了。
这很简单!只需要注释即可。
[Required]
public bool MyField { get; set; }
由此产生的迁移将是:
migrationBuilder.AddColumn<bool>(
name: "MyField",
table: "MyTable",
nullable: false,
defaultValue: false);
如果您需要true,请在更新数据库之前在迁移中将defaultValue更改为true
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; }
}
}