it-swarm.com.de

Festlegen des Standardwerts einer DateTime-Eigenschaft auf DateTime.Now innerhalb des System.ComponentModel-Standardwerts Attrbute

Weiß jemand, wie ich den Standardwert für eine DateTime-Eigenschaft mithilfe des System.ComponentModel DefaultValue-Attributs angeben kann?

zum Beispiel versuche ich das:

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

Und es erwartet, dass der Wert ein konstanter Ausdruck ist.

Dies steht im Zusammenhang mit der Verwendung mit ASP.NET Dynamic Data. Ich möchte die DateCreated-Spalte nicht mit einem Gerüst versehen, sondern einfach DateTime.Now bereitstellen, wenn sie nicht vorhanden ist. Ich verwende das Entity Framework als meine Datenschicht

Prost,

Andrew

84
REA_ANDREW

Dies ist mit einem Attribut nicht möglich, da es sich lediglich um Metainformationen handelt, die zur Kompilierungszeit generiert wurden. Fügen Sie dem Konstruktor einfach Code hinzu, um das Datum bei Bedarf zu initialisieren, einen Trigger zu erstellen und fehlende Werte in der Datenbank zu verarbeiten, oder implementieren Sie den Getter so, dass er DateTime.Now zurückgibt, wenn das Hintergrundfeld nicht initialisiert ist.

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

   set { this.dateCreated = value; }
}

private DateTime? dateCreated = null;
89

Fügen Sie unten der DateTime-Eigenschaft hinzu

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
21
user2660763

Es gibt keinen Grund, warum ich mir vorstellen kann, dass es nicht möglich sein sollte, ein Attribut zu verwenden. Möglicherweise befindet es sich im Rückstand von Microsoft. Wer weiß.

Die beste Lösung, die ich gefunden habe, ist die Verwendung des Parameters defaultValueSql bei der ersten Codemigration.

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

Die häufig verwendete Referenzlösung zum Festlegen im Entitätsklassenkonstruktor gefällt mir nicht, da das Datumsfeld keinen Standardwert erhält, wenn ein anderer Wert als Entity Framework einen Datensatz in diese Tabelle schreibt. Und die Idee, einen Auslöser zu verwenden, um diesen Fall zu behandeln, scheint mir einfach falsch.

20
d512

Es ist möglich und ganz einfach:

zum DateTime.MinValue

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

für jeden anderen Wert als letztes Argument von DefaultValueAttribute geben Sie eine Zeichenfolge an, die den gewünschten DateTime-Wert darstellt.

Dieser Wert muss ein konstanter Ausdruck sein und ist erforderlich, um ein Objekt (DateTime) mit TypeConverter zu erstellen.

10
DSW

Ich habe dies auf EF Core 2.1 getestet

Hier können Sie weder Konventionen noch Datenanmerkungen verwenden. Sie müssen die Fluent API verwenden.

class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .Property(b => b.Created)
            .HasDefaultValueSql("getdate()");
    }
}

Official doc

10
Sampath

Eine einfache Lösung, wenn Sie das Entity Framework verwenden, besteht darin, eine partielle Klasse hinzuzufügen und einen Konstruktor für die Entität zu definieren, da das Framework keinen definiert. Wenn Sie beispielsweise eine Entität mit dem Namen Example haben, würden Sie den folgenden Code in eine separate Datei einfügen.

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

Ich denke, die einfachste Lösung ist das Setzen

Created DATETIME2 NOT NULL DEFAULT GETDATE()

in der Spaltendeklaration und im VS2010-EntityModel-Designer die entsprechende Spalteneigenschaft festlegen StoreGeneratedPattern = Computed.

5
Robertas

Überlegen Sie einfach, ob Sie den Wert im Konstruktor Ihrer Entitätsklasse festlegen möchten

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

}
4

Ich brauchte einen UTC-Zeitstempel als Standardwert und änderte Daniels Lösung folgendermaßen:

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

Das Tutorial zu DateRangeAttribute finden Sie unter dieser großartige Blog-Beitrag

3
Nuri

Das Erstellen einer neuen Attributklasse ist ein guter Vorschlag. In meinem Fall wollte ich 'default (DateTime)' oder 'DateTime.MinValue' angeben, damit der Newtonsoft.Json-Serializer DateTime-Mitglieder ohne echte Werte ignoriert.

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

Ohne das DefaultValue-Attribut würde der JSON-Serializer "1/1/0001 12:00:00 AM" ausgeben, obwohl die DefaultValueHandling.Ignore-Option festgelegt wurde.

3
Erhhung

Da ist ein Weg. Fügen Sie diese Klassen hinzu:

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);
    }
}

Verwenden Sie DefaultDateTimeValue als Attribut für Ihre Eigenschaften. In das Validierungsattribut einzugebende Werte sind beispielsweise "Now" (Jetzt), die zur Laufzeit von einer mit einem Activator erstellten DateTime-Instanz gerendert werden. Der Quellcode ist von diesem Thread inspiriert: https://code.msdn.Microsoft.com/A-flexible-Default-Value-11c2db19 . Ich habe es geändert, damit meine Klasse mit DefaultValueAttribute anstelle eines ValidationAttribute erbt.

1
David

using System.ComponentModel.DataAnnotations.Schema;

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

Ich weiß, dass dieser Beitrag etwas alt ist, aber ich habe einen Vorschlag, der einigen helfen könnte.

Ich habe eine Aufzählung verwendet, um zu bestimmen, was im Attributkonstruktor festgelegt werden soll.

Eigentumserklärung:

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

Immobilienkonstruktor:

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

Aufzählung:

Public Enum EInitialValue
   DateTime_Now
   DateTime_Min
   DateTime_Max
End Enum
0
vincenormand

Ich habe gerade festgestellt, dass dies etwas anderes ist, aber in der neuen C # -Version können Sie dafür eine noch kürzere Version verwenden:

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

Wie Sie im Moment damit umgehen, hängt davon ab, welches Modell Sie mit Linq to SQL oder EntityFramework verwenden.

In L2S können Sie hinzufügen

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

        ExecuteDynamicInsert(instance);
    }
}

EF ist etwas komplizierter. Weitere Informationen zur EF-Geschäftslogik finden Sie unter http://msdn.Microsoft.com/en-us/library/cc716714.aspx .

0
Wizzard

Ich denke Sie können dies mit StoreGeneratedPattern = Identity (Im Eigenschaftenfenster des Modelldesigners eingestellt) tun.

Ich hätte nicht gedacht, dass das so ist, aber als ich versuchte, es herauszufinden, bemerkte ich, dass einige meiner Datumsspalten bereits standardmäßig CURRENT_TIMESTAMP() waren und andere nicht. Wenn ich das Modell überprüfe, sehe ich, dass der einzige Unterschied zwischen den beiden Spalten neben dem Namen darin besteht, dass die Spalte, die den Standardwert erhält, StoreGeneratedPattern auf Identity gesetzt hat.

Ich hätte nicht erwartet, dass das so ist, aber die Beschreibung zu lesen, macht irgendwie Sinn:

Legt fest, ob die entsprechende Spalte in der Datenbank während Einfüge- und Aktualisierungsvorgängen automatisch generiert wird.

Auch wenn dies dazu führt, dass die Datenbankspalte den Standardwert "now" hat, wird die Eigenschaft im POCO vermutlich nicht auf DateTime.Now Gesetzt. Dies war kein Problem für mich, da ich über eine angepasste .tt-Datei verfüge, in der bereits alle meine Datumsspalten automatisch auf DateTime.Now Gesetzt sind (es ist eigentlich nicht schwierig, die .tt-Datei selbst zu ändern, insbesondere wenn Sie dies getan haben) ReSharper und bekomme ein Syntax Highlighting Plugin. (Neuere Versionen von VS heben möglicherweise bereits .tt Dateien hervor, nicht sicher.))

Das Problem für mich war: Wie erhalte ich eine Standardeinstellung für die Datenbankspalte, sodass vorhandene Abfragen, bei denen diese Spalte weggelassen wird, weiterhin funktionieren? Und die obige Einstellung hat dafür funktioniert.

Ich habe es noch nicht getestet, aber es ist auch möglich, dass die Einstellung dieses Werts die Einstellung Ihres eigenen expliziten Werts beeinträchtigt. (Ich bin erst darauf gestoßen, weil EF6 Database First das Modell so für mich geschrieben hat.)

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

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