ChatGPT解决这个技术问题 Extra ChatGPT

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

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

例如我试试这个:

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

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

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

干杯,

安德鲁


D
Daniel Brückner

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

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

   set { this.dateCreated = value; }
}

private DateTime? dateCreated = null;

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

在 DateTime 属性中添加以下内容

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

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

我已经在 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 时间戳)。
d
d512

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

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

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

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


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

这是可能的并且非常简单:

DateTime.MinValue

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

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

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


我想相信这种用法对我有用,但不幸的是它没有。迁移结果; defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)
只是尝试放置一个字符串日期( "1/1/20" )而不是空字符串,并且它成功转换它。
好吧,当然,但是......实际的问题是将其设置为当前日期时间。哪一个,afaik,必须在 Fluent API(我讨厌)或数据库中完成。
B
Brandtware

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

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

很棒的答案,正是我想要的
这总是可以安全使用吗?
想不出有什么缺点,官方文档几乎没有提到自动初始化docs.microsoft.com/en-us/dotnet/csharp/programming-guide/…
是否可以添加日期格式?比如:DateTime.Now.ToString("yyyyMMddhh")
这个答案应该得到更多的支持。
T
Terence Golla

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

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

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

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

Created DATETIME2 NOT NULL DEFAULT GETDATE()

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


如果我这样做并使属性可为空,则会收到 EDMX 验证错误,因为不可为空的列映射到可空的属性。
如果您使用的是 EDMX,那么您没有使用 EF Core
E
Erhhung

创建一个新的属性类是一个很好的建议。就我而言,我想指定 '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”。


M
Muhammad Soliman

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

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

}

这对我有用。尽管在执行此操作之前我必须将 Datetime 属性设置为空。
A
Ali Kleit

使用 System.ComponentModel.DataAnnotations.Schema;

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

请检查how to answer
N
Nuri

我需要一个 UTC Timestamp 作为默认值,因此修改了 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


D
David

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

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 继承。


T
TreantBG

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

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

B
Bruno Bieri

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

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

欢迎使用 StackOverflow:如果您发布代码、XML 或数据示例,请在文本编辑器中突出显示这些行,然后单击编辑器工具栏上的“代码示例”按钮 ( { } ) 或使用键盘上的 Ctrl+K 进行格式化和语法突出它!
与 Brandtware 的回答相同stackoverflow.com/a/47528230/52277
T
Tomerikoo

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

b
bobac
public DateTime DateCreated
{
   get
   {
      return (this.dateCreated == default(DateTime))
         ? this.dateCreated = DateTime.Now
         : this.dateCreated;
   }

   set { this.dateCreated = value; }
}
private DateTime dateCreated = default(DateTime);

C
Chuck Norris

您目前如何处理这取决于您使用的是什么模型 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 稍微复杂一些,有关 EF 业务逻辑的更多信息,请参阅 http://msdn.microsoft.com/en-us/library/cc716714.aspx


v
vincenormand

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

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

D
Dave Cousineau

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

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

我没想到会这样,但阅读描述,这有点道理:

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

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

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

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


A
Aris

以下适用于 .NET 5.0

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

            set { this._DateCreated = value; }
        }

h
henqdev

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

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

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


A
Ali Bakhshandeh

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

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

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

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

M
Michel Smits

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

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

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

[DefaultDate(0)]

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