在 System.ComponentModel 默认值属性中将 DateTime 属性的默认值设置为 DateTime.Now

Posted

技术标签:

【中文标题】在 System.ComponentModel 默认值属性中将 DateTime 属性的默认值设置为 DateTime.Now【英文标题】:Setting the default value of a DateTime Property to DateTime.Now inside the System.ComponentModel Default Value Attrbute 【发布时间】:2010-10-16 00:24:46 【问题描述】:

有人知道如何使用 System.ComponentModel DefaultValue 属性为 DateTime 属性指定默认值吗?

例如我试试这个:

[DefaultValue(typeof(DateTime),DateTime.Now.ToString("yyyy-MM-dd"))]
public DateTime DateCreated  get; set; 

并且它期望值是一个常量表达式。

这是在使用 ASP.NET 动态数据的上下文中。我不想搭建 DateCreated 列,而只是提供 DateTime.Now(如果它不存在)。我使用实体框架作为我的数据层

干杯,

安德鲁

【问题讨论】:

【参考方案1】:

您不能对属性执行此操作,因为它们只是在编译时生成的元信息。如果需要,只需将代码添加到构造函数以初始化日期,创建触发器并处理数据库中的缺失值,或者以返回 DateTime.Now 的方式实现 getter(如果支持字段未初始化)。

public DateTime DateCreated

   get
   
      return this.dateCreated.HasValue
         ? this.dateCreated.Value
         : DateTime.Now;
   

   set  this.dateCreated = value; 


private DateTime? dateCreated = null;

【讨论】:

谢谢,在你编辑之前,我走另一条路,拦截了二传手。为帮助干杯:-) A get 部分可以简化为:return dateCreated ?? DateTime.Now; 如果您希望您的课程作为 POCO,此解决方案可能会出现问题。就我而言,我的课程应该与通过 WCF 传输的 POCO 课程一样清晰。 @zHs 这对我使用 Database First 和 Entity Framework 非常有用。 如果您来这里获取属性,请查看this answer。【参考方案2】:

在 DateTime 属性中添加以下内容

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

【讨论】:

这实际上是我一直在寻找的,它应该会变得更高。许多其他答案确实在插入实体时添加了当前日期,但它不会影响架构(即,将 getdate() 设为默认值)。对我来说,问题是当我想将记录直接添加到表中(使用 SQL)时,我必须提供日期(或将其保留为 NULL)。这是一个更好的解决方案。谢谢。 .Computed 用于添加和更新操作。仅将 .Identity 用于添加。 迄今为止的最佳答案:应该添加对 System.ComponentModel.DataAnnotations.Schema 的引用应该为 DatabaseGenerated 注释添加 将使用哪个时区?会是 UTC 吗? 将 ASP.NET Core 3.1 与 codefirst 迁移一起使用,不幸的是,这没有任何作用 :( 我赞成,因为这是一个很好的答案,但不适用于我的情况【参考方案3】:

我已经在 EF core 2.1

上对此进行了测试

在这里您不能使用约定或数据注释。您必须使用 Fluent API

class MyContext : DbContext

    public DbSet<Blog> Blogs  get; set; 

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    
        modelBuilder.Entity<Blog>()
            .Property(b => b.Created)
            .HasDefaultValueSql("getdate()");
    

Official doc

【讨论】:

这正是我想要的,但是由于我的属性在 BaseClass 上,所以我不能(它为 BaseClass 创建了一个新表)。然而,检查 ChangeTracker using this link 解决了它(设置 Created 和 Updated 时间戳)。【参考方案4】:

我没有理由想出它不应该通过属性来完成。它可能在微软的积压中。谁知道呢。

我找到的最佳解决方案是在代码先迁移中使用 defaultValueSql 参数。

CreateTable(
    "dbo.SomeTable",
    c => new
        
            TheDateField = c.DateTime(defaultValueSql: "GETDATE()")
        );

我不喜欢在实体类构造函数中设置它的常用参考解决方案,因为如果实体框架以外的任何东西在该表中粘贴记录,日期字段将不会获得默认值。使用触发器来处理这种情况的想法对我来说似乎是错误的。

【讨论】:

在更改和添加可为空的情况下使用 AddColumn("dbo.table", "Created", c => c.DateTime( nullable:true, defaultValueSql:"getdate()" ) ); 这不是个好主意,如果你会选择你的数据库,你需要重构这段代码。 最好同时使用构造函数和 defaultValueSql,这样你的类在有和没有 EF 的情况下都可以工作吗?【参考方案5】:

这是可能的,而且非常简单:

DateTime.MinValue

[System.ComponentModel.DefaultValue(typeof(DateTime), "")]

对于作为DefaultValueAttribute 的最后一个参数的任何其他值,指定表示所需日期时间值的字符串。

此值必须是常量表达式,并且是使用 TypeConverter 创建对象 (DateTime) 所必需的。

【讨论】:

我愿意相信这种用法对我有用,但不幸的是它没有。迁移结果; defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified) 刚刚尝试输入一个字符串日期(“1/1/20”)而不是空字符串,它转换成功。 嗯,当然,但是......实际的问题是将其设置为当前日期时间。哪一个,afaik,必须在 Fluent API(我讨厌)或数据库中完成。【参考方案6】:

刚刚发现这个正在寻找不同的东西,但在新的 C# 版本中,您可以使用更短的版本:

public DateTime DateCreated  get; set;  = DateTime.Now;

【讨论】:

很棒的答案,正是我想要的 这个总是可以安全使用吗? 想不出有什么缺点,官方文档很少提到自动初始化docs.microsoft.com/en-us/dotnet/csharp/programming-guide/… 是否可以添加日期格式?比如:DateTime.Now.ToString("yyyyMMddhh") 如果你想要一个字符串属性而不是 DateTime,那么是的,你可以将你的代码添加到初始化程序中。【参考方案7】:

如果您使用实体框架,一个简单的解决方案是添加一个部分类并为实体定义一个构造函数,因为框架没有定义一个。例如,如果您有一个名为 Example 的实体,您可以将以下代码放在单独的文件中。

namespace EntityExample

    public partial class Example : EntityObject
    
        public Example()
        
            // Initialize certain default values here.
            this._DateCreated = DateTime.Now;
        
    

【讨论】:

这是迄今为止最优雅(也可能也是预期的)问题的解决方案。但这是假设人们使用的是 EF Code First。 我就是这样做的,直到我意识到向我的实体添加一个复杂的属性会导致 EF 生成一个默认构造函数,让我无法编写自己的...【参考方案8】:

我认为最简单的解决方案是设置

Created DATETIME2 NOT NULL DEFAULT GETDATE()

在列声明和 VS2010 EntityModel 设计器中设置对应的列属性StoreGeneratedPattern = Computed

【讨论】:

如果我这样做并使属性可以为空,我会收到 EDMX 验证错误,因为不可为空的列映射到可空的属性。 如果您使用的是 EDMX,那么您没有使用 EF Core【参考方案9】:

创建一个新的属性类是一个很好的建议。在我的例子中,我想指定 'default(DateTime)' 或 'DateTime.MinValue' 以便 Newtonsoft.Json 序列化程序会忽略没有实际值的 DateTime 成员。

[JsonProperty( DefaultValueHandling = DefaultValueHandling.Ignore )]
[DefaultDateTime]
public DateTime EndTime;

public class DefaultDateTimeAttribute : DefaultValueAttribute

    public DefaultDateTimeAttribute()
        : base( default( DateTime ) )  

    public DefaultDateTimeAttribute( string dateTime )
        : base( DateTime.Parse( dateTime ) )  

如果没有 DefaultValue 属性,即使设置了 DefaultValueHandling.Ignore 选项,JSON 序列化程序也会输出“1/1/0001 12:00:00 AM”。

【讨论】:

【参考方案10】:

只需考虑在实体类的构造函数中设置其值

public class Foo

       public DateTime DateCreated  get; set; 
       public Foo()
       
           DateCreated = DateTime.Now;
       


【讨论】:

这对我有用。尽管在执行此操作之前我必须将 Datetime 属性设置为空。【参考方案11】:

使用 System.ComponentModel.DataAnnotations.Schema;

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedOn  get; private set; 

【讨论】:

请查看how to answer【参考方案12】:

我需要一个 UTC 时间戳作为默认值,因此修改了 Daniel 的解决方案,如下所示:

    [Column(TypeName = "datetime2")]
    [XmlAttribute]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "0:yyyy-MM-dd")]
    [Display(Name = "Date Modified")]
    [DateRange(Min = "1900-01-01", Max = "2999-12-31")]
    public DateTime DateModified 
        get  return dateModified; 
        set  dateModified = value;  
    
    private DateTime dateModified = DateTime.Now.ToUniversalTime();

DateRangeAttribute 教程见this awesome blog post

【讨论】:

【参考方案13】:

有办法。添加这些类:

DefaultDateTimeValueAttribute.cs

using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using Custom.Extensions;

namespace Custom.DefaultValueAttributes

    /// <summary>
    /// This class's DefaultValue attribute allows the programmer to use DateTime.Now as a default value for a property.
    /// Inspired from https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19. 
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public sealed class DefaultDateTimeValueAttribute : DefaultValueAttribute
    
        public string DefaultValue  get; set; 
        private object _value;

        public override object Value
        
            get
            
                if (_value == null)
                    return _value = GetDefaultValue();

                return _value;
            
        

        /// <summary>
        /// Initialized a new instance of this class using the desired DateTime value. A string is expected, because the value must be generated at runtime.
        /// Example of value to pass: Now. This will return the current date and time as a default value. 
        /// Programmer tip: Even if the parameter is passed to the base class, it is not used at all. The property Value is overridden.
        /// </summary>
        /// <param name="defaultValue">Default value to render from an instance of <see cref="DateTime"/></param>
        public DefaultDateTimeValueAttribute(string defaultValue) : base(defaultValue)
        
            DefaultValue = defaultValue;
        

        public static DateTime GetDefaultValue(Type objectType, string propertyName)
        
            var property = objectType.GetProperty(propertyName);
            var attribute = property.GetCustomAttributes(typeof(DefaultDateTimeValueAttribute), false)
                ?.Cast<DefaultDateTimeValueAttribute>()
                ?.FirstOrDefault();

            return attribute.GetDefaultValue();
        

        private DateTime GetDefaultValue()
        
            // Resolve a named property of DateTime, like "Now"
            if (this.IsProperty)
            
                return GetPropertyValue();
            

            // Resolve a named extension method of DateTime, like "LastOfMonth"
            if (this.IsExtensionMethod)
            
                return GetExtensionMethodValue();
            

            // Parse a relative date
            if (this.IsRelativeValue)
            
                return GetRelativeValue();
            

            // Parse an absolute date
            return GetAbsoluteValue();
        

        private bool IsProperty
            => typeof(DateTime).GetProperties()
                .Select(p => p.Name).Contains(this.DefaultValue);

        private bool IsExtensionMethod
            => typeof(DefaultDateTimeValueAttribute).Assembly
                .GetType(typeof(DefaultDateTimeExtensions).FullName)
                .GetMethods()
                .Where(m => m.IsDefined(typeof(ExtensionAttribute), false))
                .Select(p => p.Name).Contains(this.DefaultValue);

        private bool IsRelativeValue
            => this.DefaultValue.Contains(":");

        private DateTime GetPropertyValue()
        
            var instance = Activator.CreateInstance<DateTime>();
            var value = (DateTime)instance.GetType()
                .GetProperty(this.DefaultValue)
                .GetValue(instance);

            return value;
        

        private DateTime GetExtensionMethodValue()
        
            var instance = Activator.CreateInstance<DateTime>();
            var value = (DateTime)typeof(DefaultDateTimeValueAttribute).Assembly
                .GetType(typeof(DefaultDateTimeExtensions).FullName)
                .GetMethod(this.DefaultValue)
                .Invoke(instance, new object[]  DateTime.Now );

            return value;
        

        private DateTime GetRelativeValue()
        
            TimeSpan timeSpan;
            if (!TimeSpan.TryParse(this.DefaultValue, out timeSpan))
            
                return default(DateTime);
            

            return DateTime.Now.Add(timeSpan);
        

        private DateTime GetAbsoluteValue()
        
            DateTime value;
            if (!DateTime.TryParse(this.DefaultValue, out value))
            
                return default(DateTime);
            

            return value;
        
    

DefaultDateTimeExtensions.cs

using System;

namespace Custom.Extensions

    /// <summary>
    /// Inspired from https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19. See usage for more information.
    /// </summary>
    public static class DefaultDateTimeExtensions
    
        public static DateTime FirstOfYear(this DateTime dateTime)
            => new DateTime(dateTime.Year, 1, 1, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);

        public static DateTime LastOfYear(this DateTime dateTime)
            => new DateTime(dateTime.Year, 12, 31, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);

        public static DateTime FirstOfMonth(this DateTime dateTime)
            => new DateTime(dateTime.Year, dateTime.Month, 1, dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);

        public static DateTime LastOfMonth(this DateTime dateTime)
            => new DateTime(dateTime.Year, dateTime.Month, DateTime.DaysInMonth(dateTime.Year, dateTime.Month), dateTime.Hour, dateTime.Minute, dateTime.Second, dateTime.Millisecond);
    

并使用 DefaultDateTimeValue 作为属性的属性。输入到您的验证属性的值类似于“Now”,它将在运行时从使用 Activator 创建的 DateTime 实例呈现。源代码的灵感来自这个线程:https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19。我对其进行了更改,以使我的类使用 DefaultValueAttribute 而不是 ValidationAttribute 继承。

【讨论】:

【参考方案14】:

我遇到了同样的问题,但最适合我的问题如下:

public DateTime CreatedOn  get; set;  = DateTime.Now;

【讨论】:

【参考方案15】:

在 C# 版本 6 中,可以提供默认值

public DateTime fieldname  get; set;  = DateTime.Now;

【讨论】:

欢迎使用 ***:如果您发布代码、XML 或数据示例,请在文本编辑器中突出显示这些行,然后单击编辑器工具栏上的“代码示例”按钮 ( ) 或使用 Ctrl键盘上的 +K 可以很好地格式化和语法突出显示它! 同Brandtware的回答***.com/a/47528230/52277【参考方案16】:

使用EntityTypeConfiguration,我得到这样的结果:

public class UserMap : IEntityTypeConfiguration<User>

    public void Configure(EntityTypeBuilder<User> builder)
    
        //throw new NotImplementedException();
        builder.Property(u => u.Id).ValueGeneratedOnAdd();
        builder.Property(u => u.Name).IsRequired().HasMaxLength(100);
        builder.HasIndex(u => u.Email).IsUnique();
        builder.Property(u => u.Status).IsRequired();
        builder.Property(u => u.Password).IsRequired();
        builder.Property(u => u.Registration).HasDefaultValueSql("getdate()");

        builder.HasMany(u => u.DrawUser).WithOne(u => u.User);

        builder.ToTable("User");
    

【讨论】:

【参考方案17】:
public DateTime DateCreated

   get
   
      return (this.dateCreated == default(DateTime))
         ? this.dateCreated = DateTime.Now
         : this.dateCreated;
   

   set  this.dateCreated = value; 

private DateTime dateCreated = default(DateTime);

【讨论】:

【参考方案18】:

您目前如何处理这取决于您使用的是什么模型 Linq to SQL 或 EntityFramework?

在L2S中你可以添加

public partial class NWDataContext

    partial void InsertCategory(Category instance)
    
        if(Instance.Date == null)
            Instance.Data = DateTime.Now;

        ExecuteDynamicInsert(instance);
    

EF 稍微复杂一点,请参阅http://msdn.microsoft.com/en-us/library/cc716714.aspx 了解有关 EF 业务逻辑的更多信息。

【讨论】:

【参考方案19】:

我知道这篇文章有点老了,但是有一个建议可以帮助一些人。

我使用 Enum 来确定要在属性构造函数中设置什么。

财产声明:

[DbProperty(initialValue: EInitialValue.DateTime_Now)]
public DateTime CreationDate  get; set; 

属性构造函数:

Public Class DbProperty Inherits System.Attribute

    Public Property InitialValue As Object

    Public Sub New(ByVal initialValue As EInitialValue)
       Select Case initialValue
          Case EInitialValue.DateTime_Now
             Me.InitialValue = System.DateTime.Now

          Case EInitialValue.DateTime_Min
             Me.InitialValue = System.DateTime.MinValue

          Case EInitialValue.DateTime_Max
             Me.InitialValue = System.DateTime.MaxValue

       End Select

    End Sub
End Class

枚举:

Public Enum EInitialValue
   DateTime_Now
   DateTime_Min
   DateTime_Max
End Enum

【讨论】:

【参考方案20】:

认为您可以使用StoreGeneratedPattern = Identity(在模型设计器属性窗口中设置)来做到这一点。

我没想到会是这样,但在试图弄清楚时,我注意到我的一些日期列已经默认为CURRENT_TIMESTAMP(),而有些则不是。检查模型,我发现除了名称之外,两列之间的唯一区别是获得默认值的那一列将StoreGeneratedPattern 设置为Identity

我没想到会这样,但是阅读说明,这有点道理:

确定数据库中的相应列是否会在插入和更新操作期间自动生成。

此外,虽然这确实使数据库列具有“现在”的默认值,但我想它实际上并没有在 POCO 中将属性设置为DateTime.Now。这对我来说不是问题,因为我有一个自定义的 .tt 文件,它已经自动将我的所有日​​期列设置为 DateTime.Now(实际上自己修改 .tt 文件并不难,特别是如果你有 ReSharper 并获得一个语法高亮插件。(新版本的 VS 可能已经语法高亮 .tt 文件,不确定。))

对我来说,问题是:如何让数据库列具有默认值,以便省略该列的现有查询仍然有效?上面的设置适用于此。

我尚未对其进行测试,但设置它也可能会干扰设置您自己的显式值。 (我最初只是偶然发现了这一点,因为 EF6 Database First 以这种方式为我编写了模型。)

【讨论】:

【参考方案21】:

以下适用于 .NET 5.0

        private DateTime _DateCreated= DateTime.Now;
        public DateTime DateCreated
        
            get
            
                return this._DateCreated;
            

            set  this._DateCreated = value; 
        

【讨论】:

【参考方案22】:

您也可以考虑使用 DatabaseGenerated 属性,例如

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime DateCreated  get; set; 

https://docs.microsoft.com/en-us/ef/core/modeling/generated-properties?tabs=data-annotations

【讨论】:

【参考方案23】:

使用 Fluent API,在 Context 类的 OnModelCreating 函数中添加以下内容。

 builder.Property(u => u.CreatedAt).ValueGeneratedOnAdd();
 builder.Property(u => u.UpdatedAt).ValueGeneratedOnAddOrUpdate();

注意我正在使用一个单独的类型配置类。如果你在函数中做得对,就像:

builder.Enitity<User>().Property(u => u.CreatedAt).ValueGeneratedOnAdd();

【讨论】:

【参考方案24】:

我也想要这个并想出了这个解决方案(我只使用日期部分 - 默认时间作为 PropertyGrid 默认值没有意义):

public class DefaultDateAttribute : DefaultValueAttribute 
  public DefaultDateAttribute(short yearoffset)
    : base(DateTime.Now.AddYears(yearoffset).Date) 
  

这只会创建一个新属性,您可以将其添加到 DateTime 属性中。 例如。如果它默认为 DateTime.Now.Date:

[DefaultDate(0)]

【讨论】:

警告!!!!!!这非常糟糕,应该从 SO 中删除。我只是花了几个小时调试这个建议引起的问题。乍一看,它看起来不错,而且似乎可以工作。但这是一个陷阱。属性需要静态值是有原因的。它们被初始化一次。之后,值发生变化。因此,虽然您创建的第一个实例看起来不错,后续实例看起来也不错,但它们实际上都使用了第一个值。一旦你的应用程序运行了一段时间,你就会注意到这个问题并想知道为什么。在调试中,当你运行它一分钟时,它会运行良好。当心! 克里斯是对的。我发现了同样的问题。 不要使用这个答案

以上是关于在 System.ComponentModel 默认值属性中将 DateTime 属性的默认值设置为 DateTime.Now的主要内容,如果未能解决你的问题,请参考以下文章

使用 AvalonDock 2.0 时未处理的“System.ComponentModel.Win32Exception”

无法将类型为“System.Windows.Forms.SplitContainer”的对象强制转换为类型“System.ComponentModel.ISupportInitialize”

Azure DevOps Build 出现错误:找不到程序集“System.ComponentModel.Annotations”

无法在设计器中加载文件或程序集 System.Componentmodel.Annotations 4.2.0.0

在 System.ComponentModel 默认值属性中将 DateTime 属性的默认值设置为 DateTime.Now

间歇性 System.ComponentModel.Win32Exception:找不到网络路径