Установка значения по умолчанию для свойства 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)]