Establecer el valor predeterminado de una propiedad DateTime en DateTime.Now dentro de System.ComponentModel Valor predeterminado Attrbute

¿Alguien sabe cómo puedo especificar el valor predeterminado para una propiedad DateTime usando System.ComponentModel DefaultValue Attribute?

por ejemplo, trato de esto:

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

Y espera que el valor sea una expresión constante.

Esto es en el contexto del uso con ASP.NET Dynamic Data. No quiero andamiar la columna DateCreated, sino simplemente suministrar DateTime.Now si no está presente. Estoy usando Entity Framework como mi Data Layer

Aclamaciones,

Andrés

No puede hacer esto con un atributo porque solo son metainformación generada en tiempo de comstackción. Simplemente agregue código al constructor para inicializar la fecha si es necesario, cree un desencadenador y maneje los valores perdidos en la base de datos, o implemente el captador de forma tal que devuelva DateTime.Now si el campo de respaldo no se inicializa.

 public DateTime DateCreated { get { return this.dateCreated.HasValue ? this.dateCreated.Value : DateTime.Now; } set { this.dateCreated = value; } } private DateTime? dateCreated = null; 

No hay ninguna razón por la que se me ocurra que no debería ser posible hacerlo a través de un atributo. Podría estar en la cartera de pedidos de Microsoft. Quién sabe.

La mejor solución que he encontrado es usar el parámetro defaultValueSql en la primera migración del código.

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

No me gusta la solución de referencia a menudo de establecerlo en el constructor de clase de entidad porque si algo más que Entity Framework pega un registro en esa tabla, el campo de fecha no obtendrá un valor predeterminado. Y la idea de usar un disparador para manejar ese caso me parece incorrecta.

Es posible y bastante simple:

para DateTime.MinValue

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

para cualquier otro valor como último argumento de DefaultValueAttribute especifique una cadena que represente el valor DateTime deseado.

Este valor debe ser expresión constante y se requiere para crear objetos ( DateTime ) utilizando TypeConverter .

Una solución simple si está utilizando Entity Framework es añadir una clase partical y definir un constructor para la entidad ya que el framework no define uno. Por ejemplo, si tiene una entidad llamada Ejemplo, colocará el siguiente código en un archivo separado.

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

Creo que la solución más fácil es establecer

 Created DATETIME2 NOT NULL DEFAULT GETDATE() 

en la statement de columna y en VS2010, el diseñador de EntityModel establece la propiedad de columna correspondiente StoreGeneratedPattern = Calculated .

Simplemente considere establecer su valor en el constructor de su clase de entidad

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

Necesitaba una marca de tiempo UTC como valor predeterminado y, por lo tanto, modifiqué la solución de Daniel así:

  [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(); 

Para el tutorial de DateRangeAttribute, mira esta impresionante publicación de blog

Crear una nueva clase de atributo es una buena sugerencia. En mi caso, quería especificar ‘default (DateTime)’ o ‘DateTime.MinValue’ para que el serializador de Newtonsoft.Json ignore los miembros de DateTime sin valores reales.

 [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 ) ) { } } 

Sin el atributo DefaultValue, el serializador JSON generará “1/1/0001 12:00:00 AM” aunque se haya configurado la opción DefaultValueHandling.Ignore.

Agregue debajo a la propiedad DateTime

 [DatabaseGenerated(DatabaseGeneratedOption.Computed)] 
 public DateTime DateCreated { get { return (this.dateCreated == default(DateTime)) ? this.dateCreated = DateTime.Now : this.dateCreated; } set { this.dateCreated = value; } } private DateTime dateCreated = default(DateTime); 

¿Cómo lidiar con esto en este momento depende de qué modelo está utilizando Linq to SQL o EntityFramework?

En L2S puedes agregar

 public partial class NWDataContext { partial void InsertCategory(Category instance) { if(Instance.Date == null) Instance.Data = DateTime.Now; ExecuteDynamicInsert(instance); } } 

EF es un poco más complicado, vea http://msdn.microsoft.com/en-us/library/cc716714.aspx para obtener más información sobre la lógica de negocios de EF.

Acabo de encontrar esto buscando algo diferente, pero en la nueva versión de C #, puede usar una versión aún más corta para eso:

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

Sé que esta publicación es un poco antigua, pero tengo una sugerencia que puede ayudar a algunos.

Usé un Enum para determinar qué configurar en el constructor de atributos.

Declaración de propiedad:

 [DbProperty(initialValue: EInitialValue.DateTime_Now)] public DateTime CreationDate { get; set; } 

Constructor de propiedad:

 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 

Hay una manera. Agrega estas clases:

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 { ///  /// 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. ///  [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; } } ///  /// 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. ///  /// Default value to render from an instance of  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() ?.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(); var value = (DateTime)instance.GetType() .GetProperty(this.DefaultValue) .GetValue(instance); return value; } private DateTime GetExtensionMethodValue() { var instance = Activator.CreateInstance(); 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 { ///  /// Inspired from https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19. See usage for more information. ///  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); } } 

Y use DefaultDateTimeValue como un atributo para sus propiedades. El valor para ingresar a su atributo de validación son cosas como “Ahora”, que se representarán en tiempo de ejecución desde una instancia de DateTime creada con un Activador. El código fuente está inspirado en este hilo: https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19 . Lo cambié para hacer que mi clase herede con DefaultValueAttribute en lugar de ValidationAttribute.

Creo que puedes hacer esto usando StoreGeneratedPattern = Identity (establecido en la ventana de propiedades del diseñador del modelo).

No habría supuesto que así sería, pero al tratar de resolverlo noté que algunas de las columnas de mi fecha ya estaban en incumplimiento de CURRENT_TIMESTAMP() y otras no. Comprobando el modelo, veo que la única diferencia entre las dos columnas además del nombre es que la que obtiene el valor predeterminado tiene StoreGeneratedPattern configurado como Identity .

No hubiera esperado que fuera el camino, pero al leer la descripción, tiene sentido:

Determina si la columna correspondiente de la base de datos se generará automáticamente durante las operaciones de inserción y actualización.

Además, aunque esto hace que la columna de la base de datos tenga un valor predeterminado de “ahora”, supongo que en realidad no establece la propiedad para que sea DateTime.Now en el POCO. Esto no ha sido un problema para mí, ya que tengo un archivo .tt personalizado que ya configura todas mis columnas de fecha en DateTime.Now automáticamente (en realidad no es difícil modificar el archivo .tt usted mismo, especialmente si tiene ReSharper y obtiene un complemento de resaltado de syntax. (Las versiones más recientes de VS ya pueden contener syntax los archivos .tt, no estoy seguro))

El problema para mí fue: ¿cómo consigo que la columna de la base de datos tenga un valor predeterminado para que las consultas existentes que omiten esa columna sigan funcionando? Y la configuración anterior funcionó para eso.

Aún no lo he probado, pero también es posible que configurarlo impida establecer tu propio valor explícito. (Solo me topé con esto en primer lugar porque EF6 Database First me escribió el modelo de esta manera).

En la versión 6 de C # es posible proporcionar un valor predeterminado

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

utilizando System.ComponentModel.DataAnnotations.Schema;

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

También quería esto y se me ocurrió esta solución (solo estoy usando la parte de fecha, un tiempo predeterminado no tiene sentido como valor predeterminado de PropertyGrid):

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

Esto solo crea un nuevo atributo que puede agregar a su propiedad DateTime. Por ejemplo, si su valor predeterminado es DateTime.Now.Date:

 [DefaultDate(0)]