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 Dynamic Data와 함께 사용하는 맥락입니다. DateCreated 열을 스캐 폴드하고 싶지는 않지만 DateTime.Now가 없으면 제공합니다. Entity Framework를 데이터 계층으로 사용하고 있습니다.

건배,

앤드류

답변:


93

컴파일 타임에 생성 된 메타 정보 일뿐 속성으로는이를 수행 할 수 없습니다. 필요한 경우 생성자에 코드를 추가하여 날짜를 초기화하고, 트리거를 만들고 데이터베이스에서 누락 된 값을 처리하거나, 지원 필드가 초기화되지 않은 경우 DateTime.Now를 반환하는 방식으로 getter를 구현합니다.

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

   set { this.dateCreated = value; }
}

private DateTime? dateCreated = null;

2
감사합니다. 편집하기 전에 다른 방법으로 세터를 가로 채었습니다. :-) 도움을 건배
REA_ANDREW

10
get부분을 단순화 할 수있다 :return dateCreated ?? DateTime.Now;
Vsevolod Krasnov을

이 솔루션은 수업을 POCO로 원하는 경우 문제가 될 수 있습니다. 제 경우에는 WCF를 통해 전송되는 POCO 클래스만큼 명확해야합니다.
야곱

1
@zHs 이것은 Entity Framework와 함께 Database First를 사용하여 저에게 잘 맞았습니다.
Joshua 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

속성을 통해 할 수 없어야 할 이유가 없습니다. Microsoft의 백 로그에있을 수 있습니다. 누가 알아.

내가 찾은 가장 좋은 솔루션은 코드 첫 번째 마이그레이션에서 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 ()"));
이만

좋은 생각이 아닙니다. DB를 선택하려면이 코드를 리팩터링해야합니다.
출시

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 원인이 실현 될 때까지 나는 그것을 할 방법입니다
데이브 Cousineau

5

가장 쉬운 해결책은

Created DATETIME2 NOT NULL DEFAULT GETDATE()

열 선언 및 VS2010 EntityModel 디자이너에서 해당 열 속성 StoreGeneratedPattern = Computed를 설정 합니다.


이렇게하고 속성을 nullable로 설정하면 nullable이 아닌 열이 nullable 속성에 매핑되기 때문에 EDMX 유효성 검사 오류가 발생합니다.
Niklas Peter

4

새 속성 클래스를 만드는 것은 좋은 제안입니다. 제 경우에는 Newtonsoft.Json serializer가 실제 값이없는 DateTime 멤버를 무시하도록 'default (DateTime)'또는 'DateTime.MinValue'를 지정하고 싶었습니다.

[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"을 출력합니다.


4

엔티티 클래스의 생성자에 값을 설정하는 것을 고려하십시오.

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

}

이것은 나를 위해 일했습니다. Datetime이 작업을 수행하기 전에 속성을 nullable 로 설정해야했지만 .
Ahashan Alam Sojib

3

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 자습서는 이 멋진 블로그 게시물을 참조 하세요.



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를 속성에 대한 속성으로 사용하십시오. 유효성 검사 속성에 입력 할 값은 Activator로 만든 DateTime 인스턴스에서 런타임에 렌더링되는 "Now"와 같은 것입니다. 소스 코드는 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()일부는 이미 기본값으로 설정되어 있고 일부는 그렇지 않은 것으로 나타났습니다 . 모델을 확인하면 이름 외에 두 열의 유일한 차이점은 기본값을 가져 오는 열이로 StoreGeneratedPattern설정되어 있다는 것 Identity입니다.

나는 그것이 길을 기대하지 않았을 것이지만, 설명을 읽으면 이해가된다.

삽입 및 업데이트 작업 중에 데이터베이스의 해당 열이 자동 생성되는지 여부를 결정합니다.

또한 이로 인해 데이터베이스 열의 기본값이 "지금"이되지만 실제로 속성 DateTime.Now이 POCO 에 있도록 설정되지는 않은 것 같습니다 . 이미 모든 날짜 열을 DateTime.Now자동으로 설정하는 사용자 지정 .tt 파일이 있기 때문에 이것은 문제가되지 않았습니다 (특히 ReSharper가 있고 구문 강조 표시가있는 경우 .tt 파일을 직접 수정하는 것은 실제로 어렵지 않습니다). 플러그인. (최신 버전의 VS는 이미 .tt 파일의 구문을 강조 표시 할 수 있지만 확실하지 않습니다.)

나에게 문제는 : 데이터베이스 열이 기본값을 가지도록 어떻게하면 해당 열을 생략하는 기존 쿼리가 계속 작동 할 수 있습니까? 위의 설정이 효과가있었습니다.

아직 테스트하지는 않았지만 이것을 설정하면 자신의 명시 적 값을 설정하는 데 방해가 될 수도 있습니다. (EF6 Database First가 이런 방식으로 모델을 작성했기 때문에 처음에 이것을 발견했습니다.)


0

C # 버전 6에서는 기본값을 제공 할 수 있습니다.

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

1
StackOverflow에 오신 것을 환영합니다. 코드, XML 또는 데이터 샘플을 게시하는 경우 텍스트 편집기에서 해당 줄을 강조 표시하고 편집기 도구 모음에서 "코드 샘플"버튼 ({})을 클릭하거나 키보드에서 Ctrl + K를 사용하여 형식을 멋지게 지정하세요. 구문 강조 표시!
WhatsThePoint

1
Brandtware의 답변과 동일 stackoverflow.com/a/47528230/52277
Michael Freidgeim

-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 분 동안 실행하면 정상적으로 실행됩니다. 조심하세요!
크리스 하인즈

3
크리스가 옳다. 나는 같은 문제를 발견했다. 이 대답을 사용하지 마십시오 .
sohtimsso1970
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.