Установка значения по умолчанию для свойства DateTime в DateTime.Now внутри значения System.ComponentModel Default Attrbute

Кто-нибудь знает, как я могу указать значение по умолчанию для свойства DateTime, используя атрибут System.ComponentModel DefaultValue?

например, я пробую это:

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

И он ожидает, что значение будет постоянным выражением.

Это в контексте использования с динамическими данными ASP.NET. Я не хочу выравнивать столбец DateCreated, но просто поставляю DateTime.Now, если его нет. Я использую Entity Framework в качестве уровня данных

Приветствия,

Эндрю

Ответ 1

Вы не можете сделать это с помощью атрибута, потому что это всего лишь метаинформация, сгенерированная во время компиляции. Просто добавьте код в конструктор для инициализации даты, если это необходимо, создайте триггер и обработайте отсутствующие значения в базе данных или внедрите getter таким образом, чтобы он возвращал DateTime.Now, если поле поддержки не инициализировано.

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

   set { this.dateCreated = value; }
}

private DateTime? dateCreated = null;

Ответ 2

Добавьте ниже свойство DateTime

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

Ответ 3

Нет причин, по которым я могу придумать, что это невозможно сделать через атрибут. Возможно, это связано с отставанием Microsoft. Кто знает.

Лучшим решением, которое я нашел, является использование параметра defaultValueSql в первой миграции кода.

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

Мне не нравится частое ссылочное решение по его установке в конструкторе класса сущности, потому что если что-либо, кроме Entity Framework, вставляет в эту таблицу запись, поле даты не получит значение по умолчанию. И идея использования триггера для обработки этого случая просто кажется мне неправильной.

Ответ 4

Это возможно и довольно просто:

для DateTime.MinValue

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

для любого другого значения в качестве последнего аргумента DefaultValueAttribute укажите строку, которая представляет желаемое значение DateTime.

Это значение должно быть постоянным выражением и требуется для создания объекта (DateTime) с помощью TypeConverter.

Ответ 5

Я проверил это на EF Core 2.1

Здесь вы не можете использовать условные обозначения или аннотации данных. Вы должны использовать Свободный 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()");
    }
}

Официальный документ

Ответ 6

Простым решением, если вы используете Entity Framework, является добавление partical-класса и определение конструктора для объекта, поскольку среда не определяет его. Например, если у вас есть объект с именем Example, вы бы поместили следующий код в отдельный файл.

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

Ответ 7

Я думаю, что самым простым решением является установка

Created DATETIME2 NOT NULL DEFAULT GETDATE()

в объявлении столбца, а в VS2010 дизайнер EntityModel задает соответствующее свойство столбца StoreGeneratedPattern = Computed.

Ответ 8

Просто подумайте об установке его значения в конструкторе класса сущности

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

}

Ответ 9

Мне нужна отметка времени 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 см. этот ужасный пост в блоге

Ответ 10

Создание нового класса атрибутов - хорошее предложение. В моем случае я хотел указать "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 выводит "1/1/0001 12:00:00 AM", даже если установлен параметр DefaultValueHandling.Ignore.

Ответ 11

Есть способ. Добавьте эти классы:

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 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 как атрибут ваших свойств. Значение для ввода вашего атрибута проверки - это такие вещи, как "Сейчас", которые будут отображаться во время выполнения из экземпляра DateTime, созданного с помощью Activator. Исходный код вдохновлен этим потоком: https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19. Я изменил его, чтобы мой класс наследовал с DefaultValueAttribute вместо ValidationAttribute.

Ответ 12

использование System.ComponentModel.DataAnnotations.Schema;

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

Ответ 13

Как вы справляетесь с этим в данный момент, зависит от того, какую модель вы используете Linq для 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.

Ответ 14

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

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

Ответ 15

Я знаю, что этот пост немного стар, но есть предложение, которое может помочь кому-то.

Я использовал 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

Ответ 16

Я думаю, вы можете сделать это, используя StoreGeneratedPattern = Identity (установленный в окне свойств конструктора моделей).

Я бы не догадался, что это будет, как это сделать, но, пытаясь понять это, я заметил, что некоторые из моих столбцов даты уже не соответствуют CURRENT_TIMESTAMP(), а некоторые - нет. Проверяя модель, я вижу, что единственное различие между двумя столбцами, кроме имени, заключается в том, что значение, получающее значение по умолчанию, StoreGeneratedPattern установлено на Identity.

Я бы не ожидал, что это будет так, но, читая описание, это имеет смысл:

Определяет, будет ли соответствующий столбец в базе данных автоматически генерироваться во время операций вставки и обновления.

Кроме того, в то время как это делает столбец базы данных значением по умолчанию "now", я думаю, он фактически не устанавливает свойство DateTime.Now в POCO. Это не было проблемой для меня, поскольку у меня есть настроенный файл .tt, который уже автоматически устанавливает все мои столбцы даты в DateTime.Now (на самом деле нетрудно изменить файл .tt самостоятельно, особенно если у вас есть ReSharper и получить плагин подсветки синтаксиса (более новые версии VS могут уже синтаксически выделить файлы .tt, не уверены.))

Проблема для меня: как мне получить столбец базы данных по умолчанию, чтобы существующие запросы, которые опускали этот столбец, все еще работают? И вышеприведенная настройка работала для этого.

Я еще не тестировал его, но также возможно, что установка этого будет мешать установке вашего собственного явного значения. (Я только наткнулся на это, в первую очередь потому, что EF6 Database First написал для меня эту модель.)

Ответ 17

Просто нашел, что это ищет что-то другое, но в новой версии С# вы можете использовать для этого еще более короткую версию:

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

Ответ 18

Я столкнулся с той же проблемой, но та, которая работает для меня лучше всего, ниже:

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

Ответ 19

В С# версии 6 возможно предоставить значение по умолчанию

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

Ответ 20

Я также хотел это и придумал это решение (я использую только часть даты - время по умолчанию не имеет смысла как по умолчанию для PropertyGrid):

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

Это просто создает новый атрибут, который вы можете добавить к свойству DateTime. Например. если по умолчанию используется DateTime.Now.Date:

[DefaultDate(0)]