是否有“优雅”的方式为特定属性赋予默认值?
也许通过 DataAnnotations,类似于:
[DefaultValue("true")]
public bool Active { get; set; }
谢谢你。
this.Active = true;
中尝试?我认为在获取时数据库值将优先,但如果新建然后附加实体以进行更新而不首先获取,请小心,因为更改跟踪可能在您想要更新值时看到这一点.评论因为我很久没用EF了,感觉这是在摸黑。
public bool Inactive { get; set; }
😉
您可以通过手动编辑代码先迁移来做到这一点:
public override void Up()
{
AddColumn("dbo.Events", "Active", c => c.Boolean(nullable: false, defaultValue: true));
}
已经有一段时间了,但给别人留了个便条。我通过属性实现了所需的功能,并根据需要使用该属性装饰了模型类字段。
[SqlDefaultValue(DefaultValue = "getutcdate()")]
public DateTime CreatedDateUtc { get; set; }
得到了这2篇文章的帮助:
CodePlex 上的 EF
安迪·梅哈利克博客
我做了什么:
定义属性
[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());
[SqlDefaultValue(DefaultValue = "getutcdate()")]
放在每个实体上。 1) 只需删除 modelBuilder.Conventions.Add( new AttributeToColumnAnnotationConvention<SqlDefaultValueAttribute, string>("SqlDefaultValue", (p, attributes) => attributes.Single().DefaultValue));
2) 添加 modelBuilder.Properties().Where(x => x.PropertyType == typeof(DateTime)).Configure(c => c.HasColumnType("datetime2").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed).HasColumnAnnotation("SqlDefaultValue", "getdate()"));
上述答案确实有帮助,但只提供了部分解决方案。主要问题是,一旦您删除 Default value 属性,数据库中列的约束将不会被删除。所以以前的默认值仍将保留在数据库中。
这是该问题的完整解决方案,包括删除属性删除的 SQL 约束。我也在重新使用 .NET Framework 的本机 DefaultValue
属性。
用法
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
[DefaultValue("getutcdate()")]
public DateTime CreatedOn { get; set; }
为此,您需要更新 IdentityModels.cs 和 Configuration.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;
}
}
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
属性吗?如果是这样,为什么?在我的测试中,将其排除在外似乎没有任何效果。
您的模型属性不必是“自动属性”,即使这更容易。 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 属性不会自动设置你的属性值,你必须自己做
我承认我的方法逃避了整个“代码优先”的概念。但是,如果您能够仅更改表本身的默认值...它比您必须通过上面的长度要简单得多...我只是懒得做所有这些工作!
似乎海报的原始想法似乎可行:
[DefaultValue(true)]
public bool IsAdmin { get; set; }
https://i.stack.imgur.com/GGJ0g.png
在@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);
}
在 .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);
}
导致数据库中出现以下内容
https://i.stack.imgur.com/rctQH.png
注意:如果您的属性没有可为空(布尔?),您将收到以下警告
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'.
这很简单!只需用 required 注释即可。
[Required]
public bool MyField { get; set; }
由此产生的迁移将是:
migrationBuilder.AddColumn<bool>(
name: "MyField",
table: "MyTable",
nullable: false,
defaultValue: false);
如果要true,请在更新数据库之前在迁移中将defaultValue更改为true
true
怎么办?
我发现仅在实体属性上使用 Auto-Property Initializer 就足以完成工作。
例如:
public class Thing {
public bool IsBigThing{ get; set; } = false;
}
using System.ComponentModel;
[DefaultValue(true)]
public bool Active { get; set; }
在 2016 年 6 月 27 日发布的 EF 核心中,您可以使用 fluent API 设置默认值。转到 ApplicationDbContext 类,找到/创建方法名称 OnModelCreating 并添加以下流式 API。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<YourTableName>()
.Property(b => b.Active)
.HasDefaultValue(true);
}
[DefaultValue]
属性(在此处的另一个答案中描述)的方法。 stackoverflow.com/a/64803061/1462234
只需重载 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; }
}
}
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()");
}
假设您有一个名为 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");
}
嗯...我先做DB,在那种情况下,这实际上要容易得多。 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)]
对于相同的财产。
Event
对象时也没有专门将Active
设置为true
,我不确定这是否有效。对于不可为空的 bool 属性,默认值始终为false
,因此除非更改,否则这就是实体框架将保存到数据库的内容。还是我错过了什么?