Đặt giá trị mặc định của Thuộc tính DateTime thành DateTime.Ngay bên trong System.ComponentModel Giá trị mặc định Attrbute


94

Có ai biết cách tôi có thể chỉ định giá trị Mặc định cho thuộc tính DateTime bằng thuộc tính System.ComponentModel DefaultValue không?

ví dụ, tôi thử điều này:

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

Và nó mong đợi giá trị là một biểu thức không đổi.

Đây là trong bối cảnh sử dụng với Dữ liệu động ASP.NET. Tôi không muốn mở rộng cột DateCreate mà chỉ cần cung cấp DateTime.Now nếu nó không có. Tôi đang sử dụng Khung thực thể làm Lớp dữ liệu của mình

Chúc mừng,

Andrew

Câu trả lời:


93

Bạn không thể làm điều này với một thuộc tính vì chúng chỉ là thông tin meta được tạo ra tại thời điểm biên dịch. Chỉ cần thêm mã vào hàm tạo để khởi tạo ngày nếu cần, tạo trình kích hoạt và xử lý các giá trị bị thiếu trong cơ sở dữ liệu hoặc triển khai getter theo cách nó trả về DateTime.Now nếu trường sao lưu không được khởi tạo.

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

   set { this.dateCreated = value; }
}

private DateTime? dateCreated = null;

2
Cảm ơn bạn, trước khi bạn chỉnh sửa, tôi đã đi theo hướng khác và chặn bộ cài. Chúc mừng sự giúp đỡ :-)
REA_ANDREW

10
Một getphần có thể được đơn giản hóa để:return dateCreated ?? DateTime.Now;
Vsevolod Krasnov

Giải pháp này có thể là một vấn đề trong trường hợp bạn muốn các lớp của mình là POCO. Trong trường hợp của tôi, lớp của tôi phải rõ ràng như lớp POCO để được chuyển qua WCF.
Jacob

1
@zHs Điều này rất hiệu quả với tôi khi sử dụng Cơ sở dữ liệu đầu tiên với Khung thực thể.
Joshua K

1
Vui lòng xem câu trả lời này nếu bạn đến đây cho một thuộc tính.
Storm Muller

55

Thêm bên dưới vào thuộc tính DateTime

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]

3
Đây thực sự là những gì tôi đang tìm kiếm và nó sẽ ngày càng cao hơn. Nhiều câu trả lời khác có thêm ngày hiện tại khi chèn một thực thể, tuy nhiên nó không ảnh hưởng đến lược đồ (tức là đặt getdate () làm giá trị mặc định). Vấn đề đối với tôi là khi tôi muốn thêm bản ghi trực tiếp vào bảng (sử dụng SQL), tôi phải cung cấp ngày tháng (hoặc để nó NULL). Đây là một giải pháp tốt hơn nhiều. Cảm ơn.
Storm Muller

8
.Computed dành cho các hành động Thêm và Cập nhật. Chỉ sử dụng .Identity cho Thêm.
Renan Coelho

1
Câu trả lời tốt nhất cho đến nay: nó phải được nói thêm rằng một tham chiếu đến System.ComponentModel.DataAnnotations.Schema nên được bổ sung cho các chú thích DatabaseGenerated
Yazan Khalaileh

Múi giờ nào sẽ được sử dụng? Nó sẽ là UTC?
Almis

25

Không có lý do gì tôi có thể đưa ra rằng không thể thực hiện thông qua một thuộc tính. Nó có thể nằm trong công việc tồn đọng của Microsoft. Ai biết.

Giải pháp tốt nhất mà tôi đã tìm thấy là sử dụng tham số defaultValueSql trong lần di chuyển mã đầu tiên.

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

Tôi không thích giải pháp thường tham chiếu là đặt nó trong phương thức khởi tạo lớp thực thể bởi vì nếu bất kỳ thứ gì khác ngoài Entity Framework dính bản ghi trong bảng đó, trường ngày tháng sẽ không nhận được giá trị mặc định. Và ý tưởng sử dụng một trình kích hoạt để xử lý trường hợp đó dường như sai đối với tôi.


1
trong trường hợp thay đổi và thêm nullable, sử dụng AddColumn ("dbo.table", "Created", c => c.DateTime (nullable: true, defaultValueSql: "getdate ()"));
Iman

Đó không phải là ý kiến ​​hay, nếu bạn chọn db của mình, bạn cần cấu trúc lại mã này.
trả lời

22

Tôi đã thử nghiệm điều này trên EF core 2.1

Ở đây, bạn không thể sử dụng Quy ước hoặc Chú thích dữ liệu. Bạn phải sử dụng API thông thạo .

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

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

Tài liệu chính thức


12

Nó có thể và khá đơn giản:

cho DateTime.MinValue

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

cho bất kỳ giá trị nào khác làm đối số cuối cùng của DefaultValueAttributechuỗi chỉ định đại diện cho giá trị DateTime mong muốn.

Giá trị này phải là biểu thức hằng và được yêu cầu để tạo đối tượng ( DateTime) bằng cách sử dụng TypeConverter.


Tôi muốn tin rằng cách sử dụng đó phù hợp với tôi nhưng tiếc là nó đã không. Kết quả di chuyển; defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)
Abdurrahman I.

Chỉ cần cố gắng đặt một chuỗi ngày ("1/1/20") thay vì chuỗi rỗng và nó chuyển đổi thành công.
user890332

5

Một giải pháp đơn giản nếu bạn đang sử dụng Khung thực thể là thêm một lớp cụ thể và xác định một phương thức khởi tạo cho thực thể vì khung công tác không xác định một lớp. Ví dụ: nếu bạn có một thực thể có tên là Ví dụ, bạn sẽ đặt đoạn mã sau vào một tệp riêng biệt.

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

Đây là giải pháp thanh lịch nhất (và có lẽ cũng là dự định) cho vấn đề. Nhưng điều này giả sử mọi người đang sử dụng EF Code First.

1
Đây là cách tôi làm điều đó, cho đến khi tôi nhận ra rằng việc thêm một tài sản phức tạp để thực thể của tôi gây ra EF để tạo ra một constructor mặc định, để lại tôi với có cách nào để viết của riêng tôi ...
Dave Cousineau

5

Tôi nghĩ giải pháp đơn giản nhất là đặt

Created DATETIME2 NOT NULL DEFAULT GETDATE()

trong khai báo cột và trong VS2010 EntityModel designer đặt thuộc tính cột tương ứng StoreGeneratedPattern = Computed .


Nếu tôi làm như vậy và làm cho thuộc tính là nullable, tôi sẽ gặp lỗi xác thực EDMX, vì cột không thể nullable được ánh xạ tới thuộc tính nullable.
Niklas Peter,

4

Tạo một lớp thuộc tính mới là một gợi ý hay. Trong trường hợp của tôi, tôi muốn chỉ định 'default (DateTime)' hoặc 'DateTime.MinValue' để trình tuần tự Newtonsoft.Json sẽ bỏ qua các thành viên DateTime không có giá trị thực.

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

Nếu không có thuộc tính DefaultValue, trình tuần tự JSON sẽ xuất "1/1/0001 12:00:00 AM" mặc dù tùy chọn DefaultValueHandling.Ignore đã được đặt.


4

Chỉ cần xem xét đặt giá trị của nó trong hàm tạo của lớp thực thể của bạn

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

}

Điều này đã làm việc cho tôi. Mặc dù tôi đã phải đặt thuộc Datetimetính là nullable trước khi thực hiện việc này.
Ahashan Alam Sojib

3

Tôi cần Dấu thời gian UTC làm giá trị mặc định nên đã sửa đổi giải pháp của Daniel như sau:

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

Đối với hướng dẫn DateRangeAttribute, hãy xem bài đăng trên blog tuyệt vời này


3

sử dụng System.ComponentModel.DataAnnotations.Schema;

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

1
Vui lòng kiểm tra cách trả lời
Morse

2

Có một cách. Thêm các lớp sau:

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

Và sử dụng DefaultDateTimeValue làm thuộc tính cho thuộc tính của bạn. Giá trị đầu vào cho thuộc tính xác thực của bạn là những thứ như "Bây giờ", sẽ được hiển thị tại thời điểm chạy từ một phiên bản DateTime được tạo bằng Trình kích hoạt. Mã nguồn được lấy cảm hứng từ chủ đề này: https://code.msdn.microsoft.com/A-flexible-Default-Value-11c2db19 . Tôi đã thay đổi nó để làm cho lớp của tôi kế thừa với DefaultValueAttribute thay vì ValidationAttribute.


2

Tôi cũng gặp phải vấn đề tương tự, nhưng vấn đề phù hợp với tôi nhất ở bên dưới:

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

1

Chỉ thấy điều này đang tìm kiếm một cái gì đó khác biệt, nhưng trong phiên bản C # mới, bạn có thể sử dụng một phiên bản thậm chí còn ngắn hơn cho điều đó:

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

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

Cách bạn giải quyết vấn đề này vào lúc này phụ thuộc vào mô hình bạn đang sử dụng Linq to SQL hay EntityFramework?

Trong L2S, bạn có thể thêm

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

        ExecuteDynamicInsert(instance);
    }
}

EF phức tạp hơn một chút, hãy xem http://msdn.microsoft.com/en-us/library/cc716714.aspx để biết thêm thông tin về logic buisiness EF.


0

Tôi biết bài đăng này hơi cũ, nhưng có một gợi ý có thể giúp một số.

Tôi đã sử dụng Enum để xác định những gì cần đặt trong hàm tạo thuộc tính.

Kê khai tài sản:

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

Hàm tạo thuộc tính:

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

0

Tôi nghĩ bạn có thể làm điều này bằng cách sử dụng StoreGeneratedPattern = Identity(đặt trong cửa sổ thuộc tính của nhà thiết kế mô hình).

Tôi sẽ không đoán đó là cách thực hiện, nhưng trong khi cố gắng tìm hiểu, tôi nhận thấy rằng một số cột ngày tháng của tôi đã được mặc định thành CURRENT_TIMESTAMP()và một số thì không. Kiểm tra mô hình, tôi thấy rằng sự khác biệt duy nhất giữa hai cột ngoài tên là cột nhận giá trị mặc định đã StoreGeneratedPatternđược đặt thànhIdentity .

Tôi sẽ không mong đợi đó là cách, nhưng đọc mô tả, nó có ý nghĩa:

Xác định xem cột tương ứng trong cơ sở dữ liệu có được tạo tự động trong các thao tác chèn và cập nhật hay không.

Ngoài ra, trong khi điều này làm cho cột cơ sở dữ liệu có giá trị mặc định là "bây giờ", tôi đoán nó không thực sự đặt thuộc tính là DateTime.Nowtrong POCO. Đây không phải là vấn đề đối với tôi vì tôi có một tệp .tt tùy chỉnh đã đặt tất cả các cột ngày của tôi thànhDateTime.Now tự động (thực sự không khó để tự sửa đổi tệp .tt, đặc biệt nếu bạn có ReSharper và nhận được đánh dấu cú pháp plugin. (Các phiên bản VS mới hơn có thể đã tô sáng cú pháp các tệp .tt, không chắc chắn.))

Vấn đề đối với tôi là: làm cách nào để cột cơ sở dữ liệu có giá trị mặc định để các truy vấn hiện có bỏ qua cột đó vẫn hoạt động? Và cài đặt trên đã hoạt động cho điều đó.

Tôi chưa thử nghiệm nó nhưng cũng có thể cài đặt này sẽ ảnh hưởng đến việc đặt giá trị rõ ràng của riêng bạn. (Tôi chỉ tình cờ gặp điều này ngay từ đầu vì Cơ sở dữ liệu EF6 Đầu tiên đã viết mô hình cho tôi theo cách này.)


0

Trong C # Phiên bản 6, có thể cung cấp giá trị mặc định

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

1
Chào mừng bạn đến với StackOverflow: nếu bạn đăng mã, XML hoặc mẫu dữ liệu, vui lòng đánh dấu các dòng đó trong trình soạn thảo văn bản và nhấp vào nút "mẫu mã" ({}) trên thanh công cụ của trình soạn thảo hoặc sử dụng Ctrl + K trên bàn phím của bạn để định dạng độc đáo và cú pháp làm nổi bật nó!
WhatsThePoint

1
Giống như câu trả lời của Brandtware stackoverflow.com/a/47528230/52277
Michael Freidgeim

-1

Với EF 7:

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

tập lệnh di chuyển:

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

kết quả:

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

EF 7 không tồn tại, cột DateTime không thể là danh tính và chú thích không tạo tập lệnh di chuyển đó. Và không cần thiết phải thay đổi tập lệnh di chuyển theo cách thủ công, nếu đó là ý của bạn. Có những chú thích thêm vào mặc định, như đã được trả lời ở đây.
Gert Arnold

-5

Tôi cũng muốn điều này và đã đưa ra giải pháp này (Tôi chỉ sử dụng phần ngày - thời gian mặc định không có ý nghĩa như một mặc định của PropertyGrid):

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

Điều này chỉ tạo một thuộc tính mới mà bạn có thể thêm vào thuộc tính DateTime của mình. Ví dụ: nếu nó mặc định là DateTime.Now.Date:

[DefaultDate(0)]

32
CẢNH BÁO!!!!!! điều này rất tệ và cần được xóa khỏi SO. Tôi vừa dành hàng giờ để gỡ lỗi các vấn đề do đề xuất này gây ra. Thoạt nhìn, nó trông tốt và có vẻ hoạt động. Nhưng đây là một cái bẫy. Các thuộc tính yêu cầu giá trị tĩnh vì một lý do. Chúng được khởi tạo một lần. Sau đó, giá trị thay đổi. Vì vậy, mặc dù phiên bản đầu tiên bạn tạo sẽ trông ổn, và các phiên bản tiếp theo sẽ trông ổn, nhưng chúng thực sự đều sử dụng giá trị đầu tiên. Khi ứng dụng của bạn đã chạy được một thời gian, bạn sẽ nhận thấy sự cố và tự hỏi tại sao. Và trong gỡ lỗi, khi bạn chạy nó trong một phút, nó sẽ chạy tốt. CẨN THẬN!
Chris Hynes

3
Chris đúng. Tôi tìm thấy cùng một vấn đề. Không sử dụng câu trả lời này .
sohtimsso1970 10/10/13
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.