Czy ktoś wie, jak mogę określić wartość domyślną dla właściwości DateTime przy użyciu atrybutu System.ComponentModel DefaultValue?
na przykład próbuję tego:
[DefaultValue(typeof(DateTime),DateTime.Now.ToString("yyyy-MM-dd"))]
public DateTime DateCreated { get; set; }
I oczekuje, że wartość będzie stałym wyrażeniem.
Dzieje się tak w kontekście używania z danymi dynamicznymi ASP.NET. Nie chcę tworzyć szkieletu kolumny DateCreated, ale po prostu dostarczam DateTime.Now, jeśli nie jest obecny. Używam Entity Framework jako mojej warstwy danych
Twoje zdrowie,
Andrzej
źródło
get
Część można uprościć do:return dateCreated ?? DateTime.Now;
Dodaj poniżej do właściwości DateTime
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
źródło
Nie ma powodu, dla którego mógłbym wymyślić, że nie powinno to być możliwe za pomocą atrybutu. Może być w zaległościach Microsoftu. Kto wie.
Najlepszym rozwiązaniem, jakie znalazłem, jest użycie parametru defaultValueSql w pierwszej migracji kodu.
CreateTable( "dbo.SomeTable", c => new { TheDateField = c.DateTime(defaultValueSql: "GETDATE()") });
Nie podoba mi się często referencyjne rozwiązanie polegające na ustawianiu go w konstruktorze klasy jednostki, ponieważ jeśli cokolwiek innego niż Entity Framework przechowuje rekord w tej tabeli, pole daty nie otrzyma wartości domyślnej. Pomysł użycia wyzwalacza do obsługi tej sprawy wydaje mi się po prostu zły.
źródło
Testowałem to na EF Core 2.1
Tutaj nie możesz używać ani Konwencji, ani adnotacji danych. Musisz użyć interfejsu 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()"); } }
Oficjalny doc
źródło
Jest to możliwe i całkiem proste:
dla
DateTime.MinValue
[System.ComponentModel.DefaultValue(typeof(DateTime), "")]
dla dowolnej innej wartości jako ostatni argument
DefaultValueAttribute
ciągu określającego, który reprezentuje żądaną wartość DateTime.Ta wartość musi być wyrażeniem stałym i jest wymagana do utworzenia obiektu (
DateTime
) przy użyciuTypeConverter
.źródło
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)
Prostym rozwiązaniem, jeśli używasz Entity Framework, jest dodanie klasy częściowej i zdefiniowanie konstruktora dla jednostki, ponieważ struktura jej nie definiuje. Na przykład, jeśli masz jednostkę o nazwie Example, umieściłbyś następujący kod w oddzielnym pliku.
namespace EntityExample { public partial class Example : EntityObject { public Example() { // Initialize certain default values here. this._DateCreated = DateTime.Now; } } }
źródło
Myślę, że najłatwiejszym rozwiązaniem jest ustawienie
Created DATETIME2 NOT NULL DEFAULT GETDATE()
w deklaracji kolumny iw projektancie EntityModel VS2010 ustaw odpowiednią właściwość kolumny StoreGeneratedPattern = Computed .
źródło
Utworzenie nowej klasy atrybutów to dobra sugestia. W moim przypadku chciałem określić „default (DateTime)” lub „DateTime.MinValue”, aby serializator Newtonsoft.Json ignorował członków DateTime bez wartości rzeczywistych.
[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 ) ) { } }
Bez atrybutu DefaultValue serializator JSON wyprowadziłby „1/1/0001 12:00:00 AM”, mimo że ustawiono opcję DefaultValueHandling.Ignore.
źródło
Po prostu rozważ ustawienie jego wartości w konstruktorze klasy encji
public class Foo { public DateTime DateCreated { get; set; } public Foo() { DateCreated = DateTime.Now; } }
źródło
Datetime
właściwość nullable przed wykonaniem tej czynności.Potrzebowałem znacznika czasu UTC jako wartości domyślnej, więc zmodyfikowałem rozwiązanie Daniela w następujący sposób:
[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();
Aby zapoznać się z samouczkiem DateRangeAttribute, zobacz ten niesamowity wpis na blogu
źródło
using System.ComponentModel.DataAnnotations.Schema;
[DatabaseGenerated(DatabaseGeneratedOption.Computed)] public DateTime CreatedOn { get; private set; }
źródło
Jest sposób. Dodaj te zajęcia:
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); } }
I użyj DefaultDateTimeValue jako atrybutu do swoich właściwości. Wartość wprowadzana do atrybutu walidacji to rzeczy takie jak „Now”, które będą renderowane w czasie wykonywania z instancji DateTime utworzonej za pomocą Aktywatora. Kod źródłowy jest inspirowany tym wątkiem: https://code.msdn.microsoft.com/A-f flexible-Default-Value-11c2db19 . Zmieniłem to, aby moja klasa dziedziczyła z DefaultValueAttribute zamiast ValidationAttribute.
źródło
Właśnie znalazłem to szukając czegoś innego, ale w nowej wersji C # możesz użyć do tego jeszcze krótszej wersji:
public DateTime DateCreated { get; set; } = DateTime.Now;
źródło
Napotkałem ten sam problem, ale ten, który działa najlepiej, jest poniżej:
public DateTime CreatedOn { get; set; } = DateTime.Now;
źródło
public DateTime DateCreated { get { return (this.dateCreated == default(DateTime)) ? this.dateCreated = DateTime.Now : this.dateCreated; } set { this.dateCreated = value; } } private DateTime dateCreated = default(DateTime);
źródło
Jak sobie z tym teraz radzisz, zależy od tego, jakiego modelu używasz Linq do SQL lub EntityFramework?
W L2S możesz dodać
public partial class NWDataContext { partial void InsertCategory(Category instance) { if(Instance.Date == null) Instance.Data = DateTime.Now; ExecuteDynamicInsert(instance); } }
EF jest nieco bardziej skomplikowany, zobacz http://msdn.microsoft.com/en-us/library/cc716714.aspx, aby uzyskać więcej informacji na temat logiki biznesowej EF.
źródło
Wiem, że ten post jest trochę stary, ale mam sugestię, która może niektórym pomóc.
Użyłem Enum, aby określić, co ustawić w konstruktorze atrybutów.
Deklaracja własności:
[DbProperty(initialValue: EInitialValue.DateTime_Now)] public DateTime CreationDate { get; set; }
Konstruktor nieruchomości:
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:
źródło
Myślę, że możesz to zrobić za pomocą
StoreGeneratedPattern = Identity
(ustawionego w oknie właściwości projektanta modelu).Nie przypuszczałbym, że tak to zrobić, ale próbując to rozgryźć, zauważyłem, że niektóre z moich kolumn z datami już się ustawiały,
CURRENT_TIMESTAMP()
a inne nie. Po sprawdzeniu modelu widzę, że jedyną różnicą między dwiema kolumnami oprócz nazwy jest to, że ta, która otrzymuje wartość domyślną, maStoreGeneratedPattern
ustawioną wartośćIdentity
.Nie spodziewałbym się, że tak będzie, ale czytając opis, ma to sens:
Ponadto, chociaż powoduje to, że kolumna bazy danych ma domyślną wartość „teraz”, wydaje mi się, że w rzeczywistości nie ustawia ona tej właściwości
DateTime.Now
na POCO. Nie stanowiło to dla mnie problemu, ponieważ mam dostosowany plik .tt, który już ustawia wszystkie moje kolumny z datami naDateTime.Now
automatyczne (w rzeczywistości nie jest trudno samodzielnie zmodyfikować plik .tt, zwłaszcza jeśli masz ReSharper i otrzymujesz podświetlanie składni plugin. (nowsze wersje VS mogą już wyróżniać pliki .tt, nie jestem pewien.))Problem dla mnie brzmiał: jak sprawić, aby kolumna bazy danych miała wartość domyślną, aby istniejące zapytania, które pomijają tę kolumnę, nadal działały? I powyższe ustawienie zadziałało.
Nie testowałem tego jeszcze, ale możliwe jest również, że ustawienie tego będzie kolidowało z ustawieniem własnej jawnej wartości. (Natknąłem się na to tylko dlatego, że EF6 Database First napisał dla mnie model w ten sposób).
źródło
W C # w wersji 6 można podać wartość domyślną
public DateTime fieldname { get; set; } = DateTime.Now;
źródło
Z EF 7:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] Column(TypeName = "datetime2")] DateTime? Dateadded { get; set; }
skrypt migracji:
AlterColumn("myschema.mytable", "Dateadded", c => c.DateTime(nullable: false, precision: 7, storeType: "datetime2", defaultValueSql: "getutcdate()"));
wynik:
źródło
Chciałem też tego i wymyśliłem takie rozwiązanie (używam tylko części daty - domyślny czas nie ma sensu jako domyślny PropertyGrid):
public class DefaultDateAttribute : DefaultValueAttribute { public DefaultDateAttribute(short yearoffset) : base(DateTime.Now.AddYears(yearoffset).Date) { } }
Spowoduje to po prostu utworzenie nowego atrybutu, który można dodać do właściwości DateTime. Np. Jeśli domyślnie jest to DateTime.Now.Date:
[DefaultDate(0)]
źródło