将 DateTime 属性的默认值设置为 DateTime

是否有人知道如何使用 System 为 DateTime 属性指定默认值。组件模型默认值属性 OVT? ?

例如,我试着这样做:

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

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

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

干杯,

安德鲁

216275 次浏览

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

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


set { this.dateCreated = value; }
}


private DateTime? dateCreated = null;

目前如何处理这个问题取决于使用 LinqtoSQL 或 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 的业务逻辑。

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


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

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

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

这只是创建了一个新属性,您可以将其添加到 DateTime 属性中。 例如,如果它默认为日期时间,现在,日期:

[DefaultDate(0)]

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

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

我需要一个 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 教程,请参见 这篇很棒的博客文章

建议创建一个新的属性类。在我的示例中,我希望指定“ default (DateTime)”或“ DateTime”。让牛顿软件。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 属性,JSON 序列化程序将输出“1/1/000112:00:00 AM”,即使设置了 DefaultValueProcessing. Ignore 选项。

这是可能的,而且相当简单:

DateTime.MinValue

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

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

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

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

Created DATETIME2 NOT NULL DEFAULT GETDATE()

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

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

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


}

我知道这个帖子有点老,但是有一个建议可能会有所帮助。

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

我没有理由认为通过属性不可能做到这一点。它可能在微软的待办事项列表中。谁知道呢。

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

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

我不喜欢在实体类构造函数中设置它的常用参考解决方案,因为如果实体框架以外的任何东西在该表中保留了一条记录,日期字段就不会得到默认值。我觉得用触发器来处理这个案子是不对的。

有一个办法,添加这些类:

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

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

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

我没想到会是这样,但看看描述,还是有点道理的:

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

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

我的问题是: 如何让数据库列具有默认值,以便省略该列的现有查询仍然可以工作?上面的设置就是为了达到这个目的。

我还没有测试它,但是也有可能设置它会干扰设置您自己的显式值。(我之所以偶然发现这个问题,是因为 EF6数据库 First 以这种方式为我编写了这个模型。)

将以下内容添加到 DateTime 属性

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

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

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

在 C # Version 6中,可以提供一个默认值

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

使用 System.Component 模型

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

我已经在 EF Core 2.1上测试过了

这里不能使用约定或数据注释。必须使用 流利的空气污染指数

class MyContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }


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

官方文件

我也面临着同样的问题,但是对我最有效的方法是:

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

下面的代码可以在.NET 5.0中使用

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


set { this._DateCreated = value; }
}

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

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

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

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

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

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

注意,我使用的是一个单独的类型配置类:

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