System.ComponentModel DefaultValue属性を使用してDateTimeプロパティのデフォルト値を指定する方法を知っている人はいますか?
たとえば、私はこれを試してください:
[DefaultValue(typeof(DateTime),DateTime.Now.ToString("yyyy-MM-dd"))]
public DateTime DateCreated { get; set; }
そして、値は定数式であると想定しています。
これは、ASP.NET Dynamic Dataで使用するコンテキストです。 DateCreated列をスキャフォールドしたくありませんが、DateTime.Nowが存在しない場合は単純に指定します。 Entity Frameworkをデータレイヤーとして使用しています
乾杯、
アンドリュー
これらはコンパイル時に生成される単なるメタ情報であるため、属性を使用してこれを行うことはできません。必要に応じてコードをコンストラクターに追加して日付を初期化し、トリガーを作成してデータベース内の欠損値を処理するか、バッキングフィールドが初期化されていない場合にDateTime.Nowを返すようにゲッターを実装します。
public DateTime DateCreated
{
get
{
return this.dateCreated.HasValue
? this.dateCreated.Value
: DateTime.Now;
}
set { this.dateCreated = value; }
}
private DateTime? dateCreated = null;
以下をDateTimeプロパティに追加します
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
属性を介して実行できないようにする必要があるという理由はありません。 Microsoftのバックログにある可能性があります。知るか。
私が見つけた最良の解決策は、コードファーストの移行でdefaultValueSqlパラメーターを使用することです。
CreateTable(
"dbo.SomeTable",
c => new
{
TheDateField = c.DateTime(defaultValueSql: "GETDATE()")
});
Entity Framework以外の何かがそのテーブルにレコードを貼り付けた場合、日付フィールドはデフォルト値を取得しないため、エンティティクラスコンストラクターで設定することがよくある参照ソリューションは好きではありません。そして、トリガーを使用してそのケースを処理するという考えは、私には間違っているように思えます。
それは可能であり、非常に簡単です:
ために DateTime.MinValue
[System.ComponentModel.DefaultValue(typeof(DateTime), "")]
DefaultValueAttribute
の最後の引数として他の値については、目的のDateTime値を表す文字列を指定します。
この値は定数式でなければならず、DateTime
を使用してオブジェクト(TypeConverter
)を作成するために必要です。
私はこれをEFコア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()");
}
}
Entity Frameworkを使用している場合の単純なソリューションは、フレームワークでは定義されていないため、部分クラスを追加し、エンティティのコンストラクターを定義することです。たとえば、Exampleという名前のエンティティがある場合、次のコードを別のファイルに配置します。
namespace EntityExample
{
public partial class Example : EntityObject
{
public Example()
{
// Initialize certain default values here.
this._DateCreated = DateTime.Now;
}
}
}
最も簡単な解決策は設定することだと思います
Created DATETIME2 NOT NULL DEFAULT GETDATE()
列宣言およびVS2010 EntityModelデザイナーでは、対応する列プロパティを設定しますStoreGeneratedPattern = Computed。
エンティティクラスのコンストラクタで値を設定することを検討してください
public class Foo
{
public DateTime DateCreated { get; set; }
public Foo()
{
DateCreated = DateTime.Now;
}
}
デフォルト値としてUTCタイムスタンプが必要だったため、ダニエルのソリューションを次のように変更しました。
[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.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」を出力します。
やり方がある。これらのクラスを追加します。
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」のようなもので、アクティベーターで作成されたDateTimeインスタンスから実行時にレンダリングされます。ソースコードは、このスレッドからヒントを得ています: https://code.msdn.Microsoft.com/A-flexible-Default-Value-11c2db19 。 ValidationAttributeではなくDefaultValueAttributeでクラスを継承するように変更しました。
使用System.ComponentModel.DataAnnotations.Schema;
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime CreatedOn { get; private set; }
私はこの投稿が少し古いことを知っていますが、いくつかを助けるかもしれない提案があります。
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
これは別のものを探しているだけですが、新しいC#バージョンでは、さらに短いバージョンを使用できます:
public DateTime DateCreated { get; set; } = DateTime.Now;
現時点でこれに対処する方法は、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ビジネスロジックの詳細について。
I 思考 _StoreGeneratedPattern = Identity
_(モデルデザイナーのプロパティウィンドウで設定)を使用してこれを行うことができます。
私はそれがそれを行う方法だとは思っていませんでしたが、それを把握しようとすると、日付列の一部がすでにデフォルトのCURRENT_TIMESTAMP()
であり、一部はそうではないことに気付きました。モデルを確認すると、名前以外の2つの列の唯一の違いは、デフォルト値を取得する列のStoreGeneratedPattern
がIdentity
に設定されていることです。
私はそれが道であることを期待していなかったでしょうが、説明を読んで、それは一種の理にかなっています:
挿入および更新操作中に、データベース内の対応する列を自動生成するかどうかを決定します。
また、これによりデータベース列のデフォルト値が「now」になりますが、POCOで実際にプロパティを_DateTime.Now
_に設定することはないと思います。すでにすべての日付列を_DateTime.Now
_に自動的に設定するカスタマイズされた.ttファイルを持っているので、これは私にとっては問題ではありません(特にReSharperがある場合は、実際に.ttファイルを変更するのは難しくありません)構文強調プラグインを取得します(VSの新しいバージョンでは、既に.ttファイルの構文強調が行われている場合があります)。
私にとっての問題は、データベース列にデフォルトを設定して、その列を省略した既存のクエリが引き続き機能するようにする方法ですか?そして、上記の設定はそのために機能しました。
私はまだテストしていませんが、これを設定すると、独自の明示的な値の設定に干渉する可能性があります。 (EF6 Database Firstがこの方法でモデルを書いたので、私は最初にこれにつまずいただけです。)
public DateTime DateCreated
{
get
{
return (this.dateCreated == default(DateTime))
? this.dateCreated = DateTime.Now
: this.dateCreated;
}
set { this.dateCreated = value; }
}
private DateTime dateCreated = default(DateTime);