System.ComponentModelデフォルト値属性内のDateTimeプロパティのデフォルト値をDateTime.Nowに設定


94

System.ComponentModel DefaultValue属性を使用してDateTimeプロパティのデフォルト値を指定する方法を知っている人はいますか?

例えば私はこれを試します:

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

また、値は定数式であると想定しています。

これは、ASP.NET動的データでの使用に関連しています。DateCreated列を足場にしたくありませんが、DateTime.Nowが存在しない場合はそれを指定するだけです。Entity Frameworkをデータレイヤーとして使用しています

乾杯、

アンドリュー

回答:


93

これらはコンパイル時に生成される単なるメタ情報であるため、属性を使用してこれを行うことはできません。必要に応じてコンストラクターにコードを追加して日付を初期化するか、トリガーを作成してデータベースの欠損値を処理するか、バッキングフィールドが初期化されていない場合にDateTime.Nowを返すようにゲッターを実装します。

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

   set { this.dateCreated = value; }
}

private DateTime? dateCreated = null;

2
編集前に、私は別の方法でセッターをインターセプトしました。
応援よろしくお願いし

10
get:一部のように簡略化することができますreturn dateCreated ?? DateTime.Now;
フセヴォロドクラスノフ

このソリューションは、POCOとしてクラスが必要な場合に問題になる可能性があります。私の場合、私のクラスは、WCFを介して転送されるPOCOクラスと同じくらい明確でなければなりません。
ジェイコブ

1
@zHsこれは、Entity FrameworkでDatabase Firstを使用するのに非常に役立ちました。
ジョシュアK

1
属性についてここに来た場合は、この回答を参照しください。
Storm Muller

55

以下をDateTimeプロパティに追加します

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

3
これは実際に私が探していたものであり、さらに高くなるはずです。他の回答の多くは、エンティティを挿入するときに現在の日付を追加しますが、スキーマには影響しません(つまり、getdate()をデフォルト値にします)。私にとっての問題は、(SQLを使用して)テーブルに直接レコードを追加したいときに、日付を指定する(またはNULLのままにする)必要があったことです。これははるかに優れたソリューションです。ありがとう。
Storm Muller

8
.Computedは、追加および更新アクション用です。追加にのみ.Identityを使用します。
Renan Coelho

1
最善の答え:DatabaseGeneratedアノテーションにSystem.ComponentModel.DataAnnotations.Schemaへの参照を追加する必要があることを追加する必要があります
Yazan Khalaileh

どのタイムゾーンが使用されますか?UTCになりますか?
Almis

25

属性を介して実行することは不可能であるべきだと私が思いつく理由はありません。それはマイクロソフトのバックログにあるかもしれません。知るか。

私が見つけた最良の解決策は、コードの最初の移行でdefaultValueSqlパラメータを使用することです。

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

Entity Framework以外のものがそのテーブルにレコードを貼り付けた場合、日付フィールドはデフォルト値を取得しないため、エンティティクラスコンストラクターで設定することのよくあるリファレンスソリューションは好きではありません。そして、トリガーを使用してそのケースを処理するという考えは、私には間違っているようです。


1
nullableを変更して追加する場合は、AddColumn( "dbo.table"、 "Created"、c => c.DateTime(nullable:true、defaultValueSql: "getdate()"));を使用します。
イマン

データベースを選択する場合は、このコードをリファクタリングする必要があります。
一時停止

22

私はこれを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()");
    }
}

公式ドキュメント


12

それは可能で非常に簡単です:

ために DateTime.MinValue

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

DefaultValueAttribute目的のDateTime値を表す指定文字列の最後の引数として他の値の場合。

この値は定数式でなければならず、を使用してオブジェクト(DateTime)を作成するために必要ですTypeConverter


私は使用がうまくいったと信じたいのですが、残念ながらうまくいきませんでした。移行結果; defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)
Abdurrahman I.

空の文字列の代わりに文字列の日付( "1/1/20")を入力しようとしただけで、正常に変換されました。
user890332

5

Entity Frameworkを使用している場合の簡単な解決策は、フレームワークがパーティカルクラスを定義していないため、パーティカルクラスを追加し、エンティティのコンストラクターを定義することです。たとえば、Exampleという名前のエンティティがある場合、次のコードを別のファイルに配置します。

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

これは、この問題に対する最もエレガントな(そしておそらく意図された)解決策です。しかし、これは人々がEF Code Firstを使用していることを前提としています。

1
エンティティに複雑なプロパティを追加するとEFが既定のコンストラクタを生成し、独自のプロパティを作成する方法がなくなることに気づくまで、これが私のやり方です
Dave Cousineau

5

最も簡単な解決策は設定することだと思います

Created DATETIME2 NOT NULL DEFAULT GETDATE()

列宣言とVS2010 EntityModelデザイナーセットで対応する列プロパティ StoreGeneratedPattern = Computedを設定します。


このようにしてプロパティをnull可能にすると、null不可の列がnull可能プロパティにマップされるため、EDMX検証エラーが発生します。
Niklas Peter

4

新しい属性クラスを作成することをお勧めします。私の場合、 '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属性がない場合、JSONシリアライザーは、DefaultValueHandling.Ignoreオプションが設定されていても "1/1/0001 12:00:00 AM"を出力します。


4

エンティティクラスのコンストラクタで値を設定することを検討してください

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

}

これでうまくいきました。これをDatetime行う前に、プロパティをnullableに設定する必要がありましたが。
Ahashan Alam Sojib 2018年

3

デフォルト値として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チュートリアルについては、この素晴らしいブログ投稿を参照してください



2

やり方がある。これらのクラスを追加します。

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で継承するように変更しました。


2

私は同じ問題に直面しましたが、私にとって最もうまくいくものは以下です:

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

1

これが別のものを探しているのを見つけましたが、新しいC#バージョンでは、さらに短いバージョンを使用できます。

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

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);

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は少し複雑です。EFビジネスロジックの詳細については、http: //msdn.microsoft.com/en-us/library/cc716714.aspxを参照してください


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

列挙型:

Public Enum EInitialValue
   DateTime_Now
   DateTime_Min
   DateTime_Max
End Enum

0

(モデルデザイナーのプロパティウィンドウで設定)を使用してこれを実行できると思いますStoreGeneratedPattern = Identity

私はそれがそれを行う方法であるとは思っていませんでしたが、それを理解しようとしたときに、日付列の一部がすでにデフォルトになっCURRENT_TIMESTAMP()ているものとそうでないものがあることに気付きました。モデルを確認すると、名前以外の2つの列の唯一の違いは、デフォルト値を取得する列StoreGeneratedPatternIdentityです。

私はそれが道であるとは思っていませんでしたが、説明を読むと、それは一種の理にかなっています:

データベース内の対応する列が挿入および更新操作中に自動生成されるかどうかを決定します。

また、これによってデータベースの列のデフォルト値が「今」になるようになりますDateTime.Nowが、実際にはPOCOにプロパティが設定されるわけではないようです。私はすべての日付列をすでに設定しているカスタマイズされた.ttファイルを持っているので、これは私にとって問題ではありませんでしたDateTime.Now自動的に(特に、ReSharperを使用して構文の強調表示を取得している場合、自分で.ttファイルを変更するのは難しくありません)プラグイン(VSの新しいバージョンでは、.ttファイルの構文がすでにハイライトされている可能性があります。

私の問題は、データベースの列にデフォルトを設定して、その列を省略した既存のクエリが引き続き機能するようにする方法でした。そして、上記の設定はそのために機能しました。

まだテストしていませんが、これを設定すると、独自の明示的な値の設定が妨げられる可能性もあります。(EF6 Database Firstがこの方法でモデルを作成してくれたため、最初にこれに遭遇しただけです。)


0

C#バージョン6では、デフォルト値を指定できます

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

1
StackOverflowへようこそ:コード、XML、またはデータサンプルを投稿する場合は、テキストエディターでそれらの行を強調表示し、エディターのツールバーの[コードサンプル]ボタン({})をクリックするか、キーボードでCtrl + Kを使用して適切にフォーマットしてくださいそして構文はそれを強調します!
WhatsThePoint


-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]

EF 7は存在せず、DateTime列をIDにすることはできません。また、注釈はその移行スクリプトを作成しません。移行スクリプトを手動で変更する必要がない場合は、変更する必要があります。ここですでに十分に回答されているように、デフォルトを追加する注釈があります。
Gert Arnold

-5

私もこれが欲しくてこの解決策を思いつきました(私は日付部分のみを使用しています-デフォルトの時間はPropertyGridのデフォルトとして意味がありません):

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

これは、DateTimeプロパティに追加できる新しい属性を作成するだけです。たとえば、デフォルトがDateTime.Now.Dateの場合:

[DefaultDate(0)]

32
警告!!!!!!これは非常に悪く、SOから削除する必要があります。この提案によって引き起こされた問題のデバッグに何時間も費やしました。一見すると、見た目は良く、動作しているようです。しかし、これは罠です。理由のため、属性には静的な値が必要です。一度初期化されます。その後、値が変化します。したがって、最初に作成したインスタンスは問題なく見え、その後のインスタンスは問題なく見えますが、実際にはすべて最初の値を使用します。アプリがしばらくの間実行されていると、問題に気づき、なぜなのか不思議に思うでしょう。デバッグでは、1分間実行すると、正常に実行されます。注意してください!
Chris Hynes 2013年

3
クリスは正しいです。同じ問題が見つかりました。 この回答は使用しないでください
sohtimsso1970 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.