Programing

System.ComponentModel 기본값 속성 내에서 DateTime 속성의 기본값을 DateTime.Now로 설정

lottogame 2020. 9. 18. 19:12
반응형

System.ComponentModel 기본값 속성 내에서 DateTime 속성의 기본값을 DateTime.Now로 설정


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를 반환하는 방식으로 getter를 구현합니다.

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 타임 스탬프가 기본값으로 필요했기 때문에 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 자습서는 이 멋진 블로그 게시물을 참조 하세요.


새 속성 클래스를 만드는 것은 좋은 제안입니다. 제 경우에는 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"을 출력합니다.


방법이 있습니다. 다음 클래스를 추가하십시오.

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.


using System.ComponentModel.DataAnnotations.Schema;

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

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

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

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.


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

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


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;

I faced the same issue, but the one which works for me best is below:

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

In C# Version 6 it's possible to provide a default value

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

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

참고URL : https://stackoverflow.com/questions/691035/setting-the-default-value-of-a-datetime-property-to-datetime-now-inside-the-syst

반응형