可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Does any one know how I can specify the Default value for a DateTime property using the System.ComponentModel DefaultValue Attribute?
for example I try this:
[DefaultValue(typeof(DateTime),DateTime.Now.ToString("yyyy-MM-dd"))]
public DateTime DateCreated { get; set; }
And it expects the value to be a constant expression.
This is in the context of using with ASP.NET Dynamic Data. I do not want to scaffold the DateCreated column but simply supply the DateTime.Now if it is not present. I am using the Entity Framework as my Data Layer
Cheers,
Andrew
回答1:
You cannot do this with an attribute because they are just meta information generated at compile time. Just add code to the constructor to initialize the date if required, create a trigger and handle missing values in the database, or implement the getter in a way that it returns DateTime.Now if the backing field is not initialized.
public DateTime DateCreated
{
get
{
return this.dateCreated.HasValue
? this.dateCreated.Value
: DateTime.Now;
}
set { this.dateCreated = value; }
}
private DateTime? dateCreated = null;
回答2:
There's no reason I can come up with that it shouldn't be possible to do through an attribute. It might be in Microsoft's backlog. Who knows.
The best solution I have found is to use the defaultValueSql parameter in the code first migration.
CreateTable(
"dbo.SomeTable",
c => new
{
TheDateField = c.DateTime(defaultValueSql: "GETDATE()")
});
I don't like the often reference solution of setting it in the entity class constructor because if anything other than Entity Framework sticks a record in that table, the date field won't get a default value. And the idea of using a trigger to handle that case just seems wrong to me.
回答3:
It is possible and quite simple:
for DateTime.MinValue
[System.ComponentModel.DefaultValue(typeof(DateTime), "")]
for any other value as last argument of DefaultValueAttribute
specify string that represent desired DateTime value.
This value must be constant expression and is required to create object (DateTime
) using TypeConverter
.
回答4:
Add below to the DateTime property
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
回答5:
A simple solution if you are using the Entity Framework is the add a partical class and define a constructor for the entity as the framework does not define one. For example if you have an entity named Example you would put the following code in a seperate file.
namespace EntityExample
{
public partial class Example : EntityObject
{
public Example()
{
// Initialize certain default values here.
this._DateCreated = DateTime.Now;
}
}
}
回答6:
I think the easiest solution is to set
Created DATETIME2 NOT NULL DEFAULT GETDATE()
in column declaration and in VS2010 EntityModel designer set corresponding column property StoreGeneratedPattern = Computed.
回答7:
Simply consider setting its value in the constructor of your entity class
public class Foo
{
public DateTime DateCreated { get; set; }
public Foo()
{
DateCreated = DateTime.Now;
}
}
回答8:
I have tested this on EF core 2.1
Here you cannot use either Conventions or Data Annotations. You must use the 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
回答9:
I needed a UTC Timestamp as a default value and so modified Daniel's solution like this:
[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();
For DateRangeAttribute tutorial, see this awesome blog post
回答10:
Creating a new attribute class is a good suggestion. In my case, I wanted to specify 'default(DateTime)' or 'DateTime.MinValue' so that the Newtonsoft.Json serializer would ignore DateTime members without real values.
[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 ) ) { }
}
Without the DefaultValue attribute, the JSON serializer would output "1/1/0001 12:00:00 AM" even though the DefaultValueHandling.Ignore option was set.
回答11:
public DateTime DateCreated
{
get
{
return (this.dateCreated == default(DateTime))
? this.dateCreated = DateTime.Now
: this.dateCreated;
}
set { this.dateCreated = value; }
}
private DateTime dateCreated = default(DateTime);
回答12:
How you deal with this at the moment depends on what model you are using Linq to SQL or EntityFramework?
In L2S you can add
public partial class NWDataContext
{
partial void InsertCategory(Category instance)
{
if(Instance.Date == null)
Instance.Data = DateTime.Now;
ExecuteDynamicInsert(instance);
}
}
EF is a little more complicated see http://msdn.microsoft.com/en-us/library/cc716714.aspx for more info on EF buisiness logic.
回答13:
I know this post is a little old, but a have a suggestion that may help some.
I used an Enum to determine what to set in the attribute constructor.
Property declaration :
[DbProperty(initialValue: EInitialValue.DateTime_Now)]
public DateTime CreationDate { get; set; }
Property constructor :
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
回答14:
There is a way. Add these classes:
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);
}
}
And use DefaultDateTimeValue as an attribute to your properties. Value to input to your validation attribute are things like "Now", which will be rendered at run time from a DateTime instance created with an Activator. The source code is inspired from this thread: https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19. I changed it to make my class inherit with DefaultValueAttribute instead of a ValidationAttribute.
回答15:
I think you can do this using StoreGeneratedPattern = Identity
(set in the model designer properties window).
I wouldn't have guessed that would be how to do it, but while trying to figure it out I noticed that some of my date columns were already defaulting to CURRENT_TIMESTAMP()
and some weren't. Checking the model, I see that the only difference between the two columns besides the name is that the one getting the default value has StoreGeneratedPattern
set to Identity
.
I wouldn't have expected that to be the way, but reading the description, it sort of makes sense:
Determines if the corresponding column in the database will be auto-generated during insert and update operations.
Also, while this does make the database column have a default value of "now", I guess it does not actually set the property to be DateTime.Now
in the POCO. This hasn't been an issue for me as I have a customized .tt file that already sets all of my date columns to DateTime.Now
automatically (it's actually not hard to modify the .tt file yourself, especially if you have ReSharper and get a syntax highlighting plugin. (Newer versions of VS may already syntax highlight .tt files, not sure.))
The issue for me was: how do I get the database column to have a default so that existing queries that omit that column will still work? And the above setting worked for that.
I haven't tested it yet but it's also possible that setting this will interfere with setting your own explicit value. (I only stumbled upon this in the first place because EF6 Database First wrote the model for me this way.)
回答16:
Just found this looking for something different, but in the new C# version, you can use an even shorter version for that:
public DateTime DateCreated { get; set; } = DateTime.Now;
回答17:
using System.ComponentModel.DataAnnotations.Schema;
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedOn { get; private set; }
回答18:
In C# Version 6 it's possible to provide a default value
public DateTime fieldname { get; set; } = DateTime.Now;
回答19:
I also wanted this and came up with this solution (I'm only using the date part - a default time makes no sense as a PropertyGrid default):
public class DefaultDateAttribute : DefaultValueAttribute {
public DefaultDateAttribute(short yearoffset)
: base(DateTime.Now.AddYears(yearoffset).Date) {
}
}
This just creates a new attribute that you can add to your DateTime property.
E.g. if it defaults to DateTime.Now.Date:
[DefaultDate(0)]