将DateTime属性的默认值设置为System.ComponentModel内的DateTime.Now默认值Attrbute

时间:2009-03-27 18:49:39

标签: c# asp.net entity-framework asp.net-core-2.1 ef-core-2.1

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

例如我试试这个:

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

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

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

干杯,

安德鲁

24 个答案:

答案 0 :(得分:82)

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

public DateTime DateCreated
{
   get
   {
      return this.dateCreated.HasValue
         ? this.dateCreated.Value
         : DateTime.Now;
   }

   set { this.dateCreated = value; }
}

private DateTime? dateCreated = null;

答案 1 :(得分:19)

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

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

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

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

答案 2 :(得分:18)

将以下内容添加到DateTime属性

                    title: 'Wartość',
                    type: 'Numeric',
                    position: 'left',
                    fields: ['heapTotalValue', 'heapFreeValue', 'heapUsedValue'],
                    grid: true
                },{
                    title: 'Czas',
                    type: 'Time',
                    position: 'bottom',
                    fields: ['heapTotalDate', 'heapFreeDate', 'heapUsedDate'],
                    dateFormat: 'H:i:s.u',
                    fromDate: new Date('2017-05-11T04:10:00.055+02:00'),
                    toDate: new Date('2017-05-11T12:30:00.005+02:00'),
                    grid: true
                }],
                series: [{
                    type: 'line',
                    id: 'tilingChart',
                    fields:['heapTotalValue', 'heapTotalDate'],
                    yField: 'heapTotalValue',
                    xField: 'heapTotalDate'
                },{
                    type: 'line',
                    id: 'memoryChart',
                    fields:['heapFreeValue', 'heapFreeDate'],
                    xField: 'heapFreeValue',
                    yField: 'heapFreeDate'
                },{
                    type: 'line',
                    id: 'defaultChart',
                    fields:['heapUsedValue', 'heapUsedDate'],
                    xField: 'heapUsedValue',
                    yField: 'heapUsedDate'
                }]

答案 3 :(得分:10)

这很简单:

代表DateTime.MinValue

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

对于DefaultValueAttribute的最后一个参数的任何其他值,指定表示所需DateTime值的字符串。

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

答案 4 :(得分:9)

我已经在 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

答案 5 :(得分:6)

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

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

答案 6 :(得分:5)

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

Created DATETIME2 NOT NULL DEFAULT GETDATE()

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

答案 7 :(得分:4)

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

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

}

答案 8 :(得分:3)

我需要一个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

答案 9 :(得分:3)

创建新的属性类是一个很好的建议。在我的例子中,我想指定'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 :(得分:1)

有一种方法。添加这些类:

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作为属性的属性。输入验证属性的值类似于&#34; Now&#34;,它将在运行时从使用Activator创建的DateTime实例呈现。源代码的灵感来自这个帖子:https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19。我更改它以使我的类继承DefaultValueAttribute而不是ValidationAttribute。

答案 11 :(得分:1)

使用 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");
    }
}

答案 12 :(得分:1)

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

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

答案 13 :(得分:0)

认为您可以使用StoreGeneratedPattern = Identity(在模型设计器属性窗口中设置)来执行此操作。

我不会猜到会是怎么做的,但是在尝试解决这个问题时,我注意到我的一些日期列已经默认为CURRENT_TIMESTAMP()而有些不是。检查模型,我发现除了名称之外,两列之间的唯一区别是获得默认值的那一列的StoreGeneratedPattern设置为Identity

我不希望这样做,但阅读说明,这有点道理:

  

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

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

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

我还没有对它进行过测试,但设置此项也可能会影响您设置自己的显式值。 (我首先偶然发现了这一点,因为EF6 Database First以这种方式为我编写模型。)

答案 14 :(得分:0)

我知道这篇文章有点陈旧,但有一个建议可能有所帮助。

我使用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

Enum:

Public Enum EInitialValue
   DateTime_Now
   DateTime_Min
   DateTime_Max
End Enum

答案 15 :(得分:0)

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

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

答案 16 :(得分:0)

使用System.ComponentModel.DataAnnotations.Schema;

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

答案 17 :(得分:0)

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 :(得分:0)

以下适用于 .NET 5.0

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

            set { this._DateCreated = value; }
        }

答案 19 :(得分:0)

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

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

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

答案 20 :(得分:0)

您目前如何处理此问题取决于您使用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商务逻辑的更多信息。

答案 21 :(得分:-1)

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

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

答案 22 :(得分:-1)

使用EF 7:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
Column(TypeName = "datetime2")]
DateTime? Dateadded { get; set; }

迁移脚本:

AlterColumn("myschema.mytable", "Dateadded", c => c.DateTime(nullable: false, precision: 7, storeType: "datetime2", defaultValueSql: "getutcdate()"));

结果:

ALTER TABLE [MySchema].[MyTable] ADD  CONSTRAINT [DF_MySchema.MyTable_Dateadded]  DEFAULT (getutcdate()) FOR [Dateadded]

答案 23 :(得分:-4)

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

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

这只是创建一个可以添加到DateTime属性的新属性。 例如。如果默认为DateTime.Now.Date:

[DefaultDate(0)]