System.ComponentModel Varsayılan Değeri Attrbute içinde DateTime Özelliğinin varsayılan değerini DateTime.Now olarak ayarlama


98

System.ComponentModel DefaultValue Özniteliğini kullanarak bir DateTime özelliği için Varsayılan değeri nasıl belirleyebileceğimi bilen var mı?

örneğin şunu deniyorum:

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

Ve değerin sabit bir ifade olmasını bekler.

Bu, ASP.NET Dinamik Verileri ile kullanma bağlamındadır. DateCreated sütununu iskele etmek istemiyorum ama sadece DateTime.Now mevcut değilse sağlamak. Veri Katmanım olarak Entity Framework kullanıyorum

Şerefe,

Andrew

Yanıtlar:


95

Bunu bir öznitelikle yapamazsınız çünkü bunlar yalnızca derleme sırasında üretilen meta bilgilerdir. Gerekirse tarihi başlatmak için yapıcıya kod ekleyin, bir tetikleyici oluşturun ve veritabanındaki eksik değerleri işleyin veya alıcıyı DateTime.Now eğer yedekleme alanı başlatılmamışsa döndürür şekilde uygulayın.

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

   set { this.dateCreated = value; }
}

private DateTime? dateCreated = null;

2
Teşekkürler, sen düzenlemeden önce diğer tarafa gittim ve pasörün yolunu kestim. Yardım için
teşekkürler

12
Bir getbölüm şu şekilde basitleştirilebilir:return dateCreated ?? DateTime.Now;
Vsevolod Krasnov

Sınıflarınızı POCO olarak istiyorsanız bu çözüm bir sorun olabilir. Benim durumumda, sınıfım WCF aracılığıyla aktarılacak POCO sınıfı kadar net olmalıdır.
Jacob

1
@zHs Bu, Database First ile Entity Framework kullanarak benim için harika çalıştı.
Joshua K

1
Bir özellik için buraya geldiyseniz lütfen bu yanıta bakın .
Fırtına Muller

62

Aşağıya DateTime özelliğine ekleyin

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

3
Aslında aradığım şey buydu ve daha yükseğe çıkmalı. Diğer yanıtların çoğu, bir öğe eklerken geçerli tarihi ekler, ancak bu şemayı etkilemez (yani getdate () öğesini varsayılan değer yapın). Benim için sorun, doğrudan tabloya bir kayıt eklemek istediğimde (SQL kullanarak) tarihi sağlamam (veya NULL bırakmam) gerekti. Bu çok daha iyi bir çözüm. Teşekkürler.
Fırtına Muller

8
.Computed, Ekle ve Güncelle eylemleri içindir. Yalnızca Ekle için .Identity kullanın.
Renan Coelho

1
Şimdiye kadarki en iyi cevap: DatabaseGenerated ek açıklaması için System.ComponentModel.DataAnnotations.Schema'ya bir referans eklenmelidir
Yazan Khalaileh

1
Hangi saat dilimi kullanılacak? UTC mi olacak?
Almis

benim için bir cazibe gibi çalıştı.
Naxi

26

Bir öznitelik aracılığıyla yapmanın mümkün olmaması gerektiğini düşünmemin hiçbir nedeni yok. Microsoft'un birikiminde olabilir. Kim bilir.

Bulduğum en iyi çözüm, kodun ilk geçişinde defaultValueSql parametresini kullanmaktır.

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

Varlık sınıfı yapıcısında bunu ayarlamanın sıklıkla referans çözümünü sevmiyorum çünkü Entity Framework dışında herhangi bir şey bu tabloya bir kayıt yapıştırırsa, tarih alanı varsayılan bir değer almaz. Ve bu vakayı ele almak için bir tetik kullanma fikri bana yanlış geliyor.


1
null yapılabilir ekleme ve değiştirme durumunda AddColumn ("dbo.table", "Oluşturuldu", c => c.DateTime (nullable: true, defaultValueSql: "getdate ()"));
Iman

Bu iyi bir fikir değil, eğer db'nizi seçecekseniz, bu kodu yeniden düzenlemeniz gerekir.
lails

24

Bunu EF core 2.1'de test ettim

Burada ne Kuralları ne de Veri Ek Açıklamalarını kullanamazsınız. Fluent API kullanmalısınız .

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

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

Resmi belge


Bu tam olarak istediğim şeydi, ancak özelliğim bir BaseClass üzerinde olduğundan, yapamadım (BaseClass için yeni bir tablo oluşturdu). Bu bağlantıyı kullanarak ChangeTracker'ı incelemek sorunu çözdü (hem Oluşturulan hem de Güncellenen zaman damgalarını ayarlayarak).
Jeppe

12

Mümkün ve oldukça basit:

için DateTime.MinValue

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

DefaultValueAttributeistenen DateTime değerini temsil eden dizenin son bağımsız değişkeni olarak başka herhangi bir değer için.

Bu değer sabit ifade olmalıdır ve DateTimekullanarak object ( ) oluşturmak için gereklidir TypeConverter.


1
Kullanımın benim için işe yaradığına inanmak isterdim ama maalesef olmadı. Göç sonucu; defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)
Abdurrahman I.

Boş dizge yerine bir dize tarihi ("1/1/20") koymayı denedim ve başarıyla dönüştürdü.
user890332

5

Entity Framework kullanıyorsanız basit bir çözüm, bir partik sınıf eklemek ve çerçeve bir tane tanımlamadığından varlık için bir yapıcı tanımlamaktır. Örneğin, Example adında bir varlığınız varsa, aşağıdaki kodu ayrı bir dosyaya koyarsınız.

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

Bu, soruna açık ara en zarif (ve muhtemelen amaçlanan) çözümdür. Ancak bu, insanların EF Code First kullandığını varsayıyor.


5

Bence en kolay çözüm ayarlamak

Created DATETIME2 NOT NULL DEFAULT GETDATE()

sütun bildiriminde ve VS2010 EntityModel tasarımcısında ilgili sütun özelliğini ayarlayın StoreGeneratedPattern = Computed .


Bunu böyle yaparsam ve özelliği null yapılabilir yaparsam, bir EDMX doğrulama hatası alıyorum çünkü null yapılamayan bir sütun null yapılabilir bir özelliğe eşleniyor.
Niklas Peter

4

Yeni bir öznitelik sınıfı oluşturmak iyi bir öneridir. Benim durumumda, Newtonsoft.Json serileştiricisinin gerçek değerleri olmayan DateTime üyelerini yoksayması için 'default (DateTime)' veya 'DateTime.MinValue' belirtmek istedim.

[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 özniteliği olmadan JSON serileştiricisi, DefaultValueHandling.Ignore seçeneği ayarlansa bile "1/1/0001 12:00:00 AM" sonucunu verir.


4

Varlık sınıfınızın yapıcısında değerini ayarlamayı düşünün.

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

}

Bu benim için çalıştı. Yine de bunu Datetimeyapmadan önce özelliği null yapılabilir olarak ayarlamak zorunda kaldım .
Ahashan Alam Sojib

3

Varsayılan değer olarak bir UTC Zaman Damgasına ihtiyacım vardı ve Daniel'in çözümünü şu şekilde değiştirdim:

    [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 öğreticisi için bu harika blog gönderisine bakın



2

Bir yol var. Bu sınıfları ekleyin:

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

Ve özelliklerinizin özniteliği olarak DefaultDateTimeValue kullanın. Doğrulama özniteliğinize girilecek değer, "Now" gibi şeylerdir ve bir Activator ile oluşturulan bir DateTime örneğinden çalışma zamanında işlenir. Kaynak kodu şu konu dizisinden esinlenmiştir: https://code.msdn.microsoft.com/A-felix-Default-Value-11c2db19 . Sınıfımın bir ValidationAttribute yerine DefaultValueAttribute ile devralması için bunu değiştirdim.



2

Ben de aynı sorunla karşılaştım, ancak benim için en iyi olanı aşağıdadır:

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

1

C # Sürüm 6'da varsayılan bir değer sağlamak mümkündür

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

1
StackOverflow'a hoş geldiniz: Kod, XML veya veri örnekleri gönderirseniz, lütfen metin düzenleyicide bu satırları vurgulayın ve düzenleyici araç çubuğundaki "kod örnekleri" düğmesini ({}) veya klavyenizdeki Ctrl + K tuşlarını kullanarak güzel bir şekilde biçimlendirin ve sözdizimi vurgulayın!
WhatsThePoint


0
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

Şu anda bununla nasıl başa çıkacağınız Linq to SQL veya EntityFramework kullandığınız modele bağlıdır?

L2S'de ekleyebilirsiniz

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

        ExecuteDynamicInsert(instance);
    }
}

EF biraz daha karmaşıktır , EF buisiness mantığı hakkında daha fazla bilgi için http://msdn.microsoft.com/en-us/library/cc716714.aspx adresine bakın .


0

Bu yazının biraz eski olduğunu biliyorum, ancak bazılarına yardımcı olabilecek bir önerim var.

Öznitelik yapıcısında neyin ayarlanacağını belirlemek için bir Enum kullandım.

Mülkiyet beyanı:

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

Mülk yapıcısı:

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

Sıralama :

Public Enum EInitialValue
   DateTime_Now
   DateTime_Min
   DateTime_Max
End Enum

0

Bunu kullanarak yapabileceğinizi düşünüyorumStoreGeneratedPattern = Identity (model tasarımcısı özellikleri penceresinde ayarlayın).

Bunun nasıl yapılacağını tahmin edemezdim, ancak anlamaya çalışırken tarih sütunlarımdan bazılarının zaten varsayılan olduğunu CURRENT_TIMESTAMP()ve bazılarının olmadığını fark ettim . Modeli kontrol ettiğimde, iki sütun arasındaki ismin yanı sıra tek farkın varsayılan değeri alanın olarak StoreGeneratedPatternayarlanması olduğunu görüyorum Identity.

Bunun böyle olmasını beklemiyordum ama açıklamayı okumak mantıklı:

Veritabanındaki ilgili sütunun, ekleme ve güncelleme işlemleri sırasında otomatik olarak oluşturulup oluşturulmayacağını belirler.

Ayrıca, bu veritabanı sütununun "now" varsayılan değerine sahip olmasını DateTime.Nowsağlasa da , aslında özelliği POCO'da olacak şekilde ayarlamadığını tahmin ediyorum . Bu benim için bir sorun olmadı çünkü tüm tarih sütunlarımı DateTime.Nowotomatik olarak ayarlayan özelleştirilmiş bir .tt dosyam var (aslında .tt dosyasını kendiniz değiştirmek zor değil, özellikle ReSharper'a sahipseniz ve bir sözdizimi vurgulaması alıyorsanız eklenti. (VS'nin daha yeni sürümleri zaten sözdizimi .tt dosyalarını vurgulayabilir, emin değil.))

Benim için sorun şuydu: veritabanı sütununun bir varsayılana sahip olmasını nasıl sağlayabilirim, böylece bu sütunu atlayan mevcut sorgular çalışmaya devam eder? Ve yukarıdaki ayar bunun için çalıştı.

Henüz test etmedim, ancak bunu ayarlamanın kendi açık değerinizi belirlemenize engel olması da mümkündür. (Ben sadece ilk etapta tökezledim çünkü EF6 Database First modeli benim için bu şekilde yazdı.)


-1

EF 7 ile:

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
Column(TypeName = "datetime2")]
DateTime? Dateadded { get; set; }

taşıma komut dosyası:

AlterColumn("myschema.mytable", "Dateadded", c => c.DateTime(nullable: false, precision: 7, storeType: "datetime2", defaultValueSql: "getutcdate()"));

sonuç:

ALTER TABLE [MySchema].[MyTable] ADD  CONSTRAINT [DF_MySchema.MyTable_Dateadded]  DEFAULT (getutcdate()) FOR [Dateadded]

EF 7 yok, bir DateTime sütunu kimlik olamaz ve ek açıklama bu geçiş betiğini oluşturmaz. Ve eğer kastettiğiniz buysa, taşıma komut dosyasını manuel olarak değiştirmek gerekli değildir. Burada zaten fazlasıyla yanıtlandığı gibi, varsayılanı ekleyen ek açıklamalar var.
Gert Arnold

-6

Bunu da istedim ve bu çözümü buldum (Yalnızca tarih bölümünü kullanıyorum - varsayılan bir zaman bir PropertyGrid varsayılanı olarak anlamsız):

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

Bu, DateTime özelliğinize ekleyebileceğiniz yeni bir öznitelik oluşturur. Örneğin, varsayılan olarak DateTime.Now.Date ise:

[DefaultDate(0)]

33
UYARI!!!!!! bu çok kötü ve SO'dan çıkarılmalıdır. Bu önerinin neden olduğu sorunları gidermek için saatler harcadım. İlk bakışta iyi görünüyor ve işe yarıyor gibi görünüyor. Ama bu bir tuzak. Öznitelikler, bir nedenle statik değerler gerektirir. Bir kez başlatılırlar. Bundan sonra değer değişir. Dolayısıyla, oluşturduğunuz ilk örnek iyi görünecek ve sonraki örnekler iyi görünse de, aslında hepsi ilk değeri kullanır. Uygulamanız bir süre çalıştıktan sonra, sorunu fark edecek ve nedenini merak edeceksiniz. Ve hata ayıklamada, onu bir dakika çalıştırdığınızda iyi çalışacaktır. DİKKAT!
Chris Hynes

3
Chris haklı. Ben de aynı sorunu buldum. Bu cevabı kullanmayın .
sohtimsso1970
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.