关于c#:将DateTime属性的默认值设置为System.ComponentModel内的DateTime.Now默认值Attrbute

Setting the default value of a DateTime Property to DateTime.Now inside the System.ComponentModel Default Value Attrbute

是否有人知道如何使用system.componentmodel default value属性为datetime属性指定默认值?

例如,我尝试这样做:

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

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

这是在与ASP.NET动态数据一起使用的上下文中。我不想搭建datecreated列,只需提供datetime即可。如果它不存在,现在就提供。我使用实体框架作为数据层

干杯,

安得烈


您不能用属性来实现这一点,因为它们只是编译时生成的元信息。如果需要,只需向构造函数添加代码来初始化日期,创建触发器并处理数据库中缺少的值,或者以返回datetime的方式实现getter。现在,如果不初始化backing字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
public DateTime DateCreated
{
   get
   {
      return this.dateCreated.HasValue
         ? this.dateCreated.Value
         : DateTime.Now;
   }

   set { this.dateCreated = value; }
}

private DateTime? dateCreated = null;


我没有理由想到通过一个属性是不可能做到的。这可能是微软的积压工作。谁知道呢。

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

1
2
3
4
5
6
CreateTable(
   "dbo.SomeTable",
    c => new
        {
            TheDateField = c.DateTime(defaultValueSql:"GETDATE()")
        });

我不喜欢经常在实体类构造函数中设置它的引用解决方案,因为如果实体框架以外的任何东西在该表中粘贴了一个记录,那么日期字段将不会得到默认值。我觉得用扳机来处理这个案子的想法是错误的。


在下面添加到datetime属性

1
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]


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

对于DateTime.MinValue

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

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

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


我在EF核心2.1上测试过这个

这里既不能使用约定,也不能使用数据注释。必须使用Fluent API。

1
2
3
4
5
6
7
8
9
10
11
class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

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

官方文档


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

1
2
3
4
5
6
7
8
9
10
11
namespace EntityExample
{
    public partial class Example : EntityObject
    {
        public Example()
        {
            // Initialize certain default values here.
            this._DateCreated = DateTime.Now;
        }
    }
}


我认为最简单的解决办法是

1
Created DATETIME2 NOT NULL DEFAULT GETDATE()

在列声明和VS2010 EntityModel设计器中,设置相应的列属性storeGeneratedPattern=computed。


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

1
2
3
4
5
6
7
8
9
public class Foo
{
       public DateTime DateCreated { get; set; }
       public Foo()
       {
           DateCreated = DateTime.Now;
       }

}


创建一个新的属性类是一个很好的建议。在我的示例中,我希望指定"default(datetime)"或"datetime.minvalue",以便newtonsoft.json序列化程序忽略不带实值的datetime成员。

1
2
3
4
5
6
7
8
9
10
11
12
[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属性,JSON序列化程序将输出"1/1/0001 12:00:00 am",即使设置了defaultValueHandling.ignore选项。


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

1
2
3
4
5
6
7
8
9
10
    [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();

有关daterageattribute教程,请参阅这篇精彩的博客文章


有办法。添加这些类:

默认日期时间值attribute.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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;
        }
    }
}

默认日期时间扩展.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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创建的日期时间实例中呈现。源代码的灵感来自于这个线程:https://code.msdn.microsoft.com/a-flexible-default-value-11c2db19。我更改了它,使我的类用defaultValueAttribute继承,而不是用validationAttribute继承。


我认为您可以使用StoreGeneratedPattern = Identity(在"模型设计器属性"窗口中设置)。

我不知道该怎么做,但当我想弄清楚的时候,我注意到我的一些日期列已经默认为CURRENT_TIMESTAMP(),而有些没有。检查模型,我发现除了名称之外,两列之间唯一的区别是,获得默认值的一列已经将StoreGeneratedPattern设置为EDOCX1。〔3〕。

我本不希望是这样,但读了描述,就有点道理了:

0

此外,虽然这会使数据库列的默认值为"now",但我想它实际上并没有在POCO中将属性设置为DateTime.Now。这对我来说不是问题,因为我有一个定制的.t t文件,它已经自动将所有日期列设置为DateTime.Now(实际上,自己修改.tt文件并不困难,特别是如果你有resharper和一个突出显示语法的插件。(较新版本的vs可能已经语法突出显示.tt文件,不确定。))

对我来说,问题是:如何使数据库列具有默认值,以便忽略该列的现有查询仍然有效?上面的设置也起了作用。

我还没有测试过它,但是设置它也可能会干扰设置您自己的显式值。(我一开始只是偶然发现了这一点,因为EF6数据库首先用这种方式为我编写了模型。)


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

1
public DateTime DateCreated { get; set; } = DateTime.Now;

使用system.componentModel.dataAnnotations.schema;

1
2
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedOn { get; private set; }


2


目前如何处理这一问题取决于您使用的是什么模型LinqToSQL或EntityFramework?

在L2s中,您可以添加

1
2
3
4
5
6
7
8
9
10
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 business逻辑的更多信息。


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

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

属性声明:

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

属性构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

枚举:

1
2
3
4
5
Public Enum EInitialValue
   DateTime_Now
   DateTime_Min
   DateTime_Max
End Enum

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

2


我也希望这样,并提出了这个解决方案(我只使用日期部分-默认时间作为属性网格默认值没有意义):

1
2
3
4
5
public class DefaultDateAttribute : DefaultValueAttribute {
  public DefaultDateAttribute(short yearoffset)
    : base(DateTime.Now.AddYears(yearoffset).Date) {
  }
}

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

1
[DefaultDate(0)]