Установка значения по умолчанию свойства DateTime в DateTime.Теперь внутри системы.ComponentModel Значение По Умолчанию Attrbute
кто-нибудь знает, как я могу указать значение по умолчанию для свойства DateTime с помощью системы.Атрибут ComponentModel DefaultValue?
например, я пытаюсь это:
[DefaultValue(typeof(DateTime),DateTime.Now.ToString("yyyy-MM-dd"))]
public DateTime DateCreated { get; set; }
и он ожидает, что значение должно быть константным выражением.
это в контексте использования с ASP.NET динамические данные. Я не хочу скомпоновать столбец DateCreated, а просто предоставить DateTime.Теперь, если его нет. Я использую Entity Framework в качестве своих данных Слой
спасибо,
Андрей
19 ответов:
вы не можете сделать это с атрибутом, потому что они просто метаинформация, генерируемая во время компиляции. Просто добавьте код в конструктор для инициализации даты, если это необходимо, создайте триггер и обработайте отсутствующие значения в базе данных или реализуйте геттер таким образом, чтобы он возвращал DateTime.Теперь, если резервное поле не инициализировано.
public DateTime DateCreated { get { return this.dateCreated.HasValue ? this.dateCreated.Value : DateTime.Now; } set { this.dateCreated = value; } } private DateTime? dateCreated = null;
нет причин я могу придумать, что это не должно быть возможно сделать через атрибут. Это может быть в отставании 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
.
простое решение, если вы используете Entity Framework, - это добавить partical класс и определить конструктор для сущности, поскольку платформа не определяет его. Например, если у вас есть объект с именем 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 designer установите соответствующее свойство столбца StoreGeneratedPattern = Вычисляемые.
просто рассмотрите возможность установки его значения в конструкторе вашего класса сущностей
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 сериализатор JSON будет выводить "1/1/0001 12: 00: 00 AM", даже если DefaultValueHandling.Параметр игнорировать был установлен.
public DateTime DateCreated { get { return (this.dateCreated == default(DateTime)) ? this.dateCreated = DateTime.Now : this.dateCreated; } set { this.dateCreated = value; } } private DateTime dateCreated = default(DateTime);
Как вы справляетесь с этим на данный момент зависит от того, какую модель вы используете 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 buisiness logic.
просто нашел это, ища что-то другое, но в новой версии C# вы можете использовать еще более короткую версию для этого:
public DateTime DateCreated { get; set; } = DateTime.Now;
Я знаю, что этот пост немного старый, но есть предложение, которое может помочь некоторым.
Я использовал перечисление, чтобы определить, что установить в конструкторе атрибутов.
объявление :
[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
есть способ. Добавьте следующие классы:
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 в качестве атрибута для ваших свойств. Значение для ввода в атрибут проверки-это такие вещи, как" сейчас", которые будут отображаться во время выполнения из экземпляра DateTime, созданного с помощью активатора. Исходный код вдохновлен этой темой: https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19. я изменил его, чтобы сделать мой класс наследуется с DefaultValueAttribute вместо ValidationAttribute.
Я думаю вы можете сделать это с помощью
StoreGeneratedPattern = Identity
(задается в окне свойств конструктора моделей).Я бы не догадался, что это будет так, но, пытаясь понять это, я заметил, что некоторые из моих столбцов даты уже по умолчанию
CURRENT_TIMESTAMP()
а кто-то нет. Просмотрев модели, я вижу, что единственное различие между двумя колоннами к тому же имя, как значение по умолчаниюStoreGeneratedPattern
значениеIdentity
.I не ожидал бы, что это будет так, но, читая описание, это имеет смысл:
определяет, будет ли соответствующий столбец в базе данных автоматически генерироваться во время операций вставки и обновления.
кроме того, хотя это делает столбец базы данных иметь значение по умолчанию "сейчас", я думаю, что на самом деле он не устанавливает свойство быть
DateTime.Now
в POCO. Это не было проблемой для меня, поскольку у меня есть настроенный файл .tt, который уже устанавливает все мои столбцы даты вDateTime.Now
автоматически (на самом деле нетрудно изменить файл .tt самостоятельно, особенно если у вас есть ReSharper и получить плагин подсветки синтаксиса. (Более новые версии VS могут уже выделять файлы синтаксиса. tt, не уверен.))проблема для меня была: как мне получить столбец базы данных по умолчанию, чтобы существующие запросы, которые опускают этот столбец, все еще работали? И вышеприведенная настройка работала для этого.
Я еще не тестировал его, но это также возможно, что установка этого будет мешать установке вашего собственного явного значения. (Я только наткнулся на это в первую очередь, потому что база данных EF6 впервые написала модель для меня таким образом.)
В C# версии 6 можно указать значение по умолчанию
public DateTime fieldname { get; set; } = DateTime.Now;
использование системы.ComponentModel.DataAnnotations.Схема;
[DatabaseGenerated(DatabaseGeneratedOption.Computed)] public DateTime CreatedOn { get; private set; }
Я проверил это на EF core 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()"); } }
Я также хотел этого и придумал это решение (я использую только часть даты - время по умолчанию не имеет смысла как значение по умолчанию PropertyGrid):
public class DefaultDateAttribute : DefaultValueAttribute { public DefaultDateAttribute(short yearoffset) : base(DateTime.Now.AddYears(yearoffset).Date) { } }
Это просто создает новый атрибут, который можно добавить к свойству DateTime. Например, если он по умолчанию имеет значение DateTime.Сейчас.Дата:
[DefaultDate(0)]