2013-01-09 22 views
7

Tôi đang lưu đối tượng Giỏ hàng vào cơ sở dữ liệu có ngày giờ không có giá trị. Đây là lỗi tôi nhận được:Tại sao mã EF5 đầu tiên sử dụng datetime2 khi chèn một datetime nullable vào cơ sở dữ liệu?

Chuyển đổi kiểu dữ liệu datetime2 thành kiểu dữ liệu datetime dẫn đến giá trị ngoài phạm vi.

Có một số bài đăng ngăn xếp chồng lên tài liệu sửa lỗi cho vấn đề này. Tuy nhiên, khi mã đầu tiên tạo cơ sở dữ liệu, nó sẽ tạo trường như là một DateTime (cho phép null). Nhưng đối với một số lý do, mã đầu tiên cố gắng chèn bằng cách sử dụng một trường DateTime2.

Tôi tự hỏi tại sao EF tạo ra trường một chiều, nhưng chèn bằng cách sử dụng một loại khác cho cùng một trường.

Đây là đối tượng miền:

using System; 
using System.Collections.Generic; 

namespace Core.Domain.Cart 
{ 
    public partial class Cart : BaseEntity, ILocalizedEntity 
    { 
     private ICollection<Catalog> _catalogs; 

     /// <summary> 
     /// Gets or sets the name 
     /// </summary> 
     public virtual string Name { get; set; } 

     /// <summary> 
     /// Gets or sets the zone identifier 
     /// </summary> 
     public virtual int ZoneId { get; set; } 

     /// <summary> 
     /// Gets or sets the brand identifier 
     /// </summary> 
     public virtual int BrandId { get; set; } 

     /// <summary> 
     /// Gets or sets the customer type identifier 
     /// </summary> 
     public virtual int CustomerTypeId { get; set; } 

     /// <summary> 
     /// Gets or sets the date and time of the opening of a cart 
     /// </summary> 
     public virtual DateTime? OpeningDateUtc { get; set; } 

     /// <summary> 
     /// Gets or sets the date and time of the closing of a cart 
     /// </summary> 
     public virtual DateTime? ClosingDateUtc { get; set; } 

     /// <summary> 
     /// Gets or sets a value indicating whether the entity is online or not 
     /// </summary> 
     public virtual bool IsOnline { get; set; } 

     /* Truncated for relevance */ 
    }  
} 

Mô hình:

using FluentValidation.Attributes; 
using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using System.Web.Mvc; 
using Telerik.Web.Mvc; 


namespace Admin.Models.Cart 
{ 
     [Validator(typeof(CartValidator))] 
     public partial class CartModel : BaseNopEntityModel, ILocalizedModel<CartLocalizedModel> 
     {    
      public CartModel() 
      { 
       Locales = new List<CartLocalizedModel>(); 
       Catalogs = new List<CatalogModel>(); 
       UnassociatedCatalogs = new List<CatalogModel>(); 
      } 
      [NopResourceDisplayName("Admin.Carts.Fields.Name")] 
      [AllowHtml] 
      public string Name { get; set; } 

      //Zone dropdown 
      [NopResourceDisplayName("Admin.Carts.Fields.ZoneList")] 
      public SelectList ZoneList { get; set; }  //The dropdown with zones 
      public int ZoneId { get; set; }     //The selected value of the dropdown once the form is submitted 
      public string ZoneName { get; set; }   //The name of the zone to display in data-grid List view. 

      //Brand dropdown 
      [NopResourceDisplayName("Admin.Carts.Fields.BrandList")] 
      public SelectList BrandList { get; set; }  //The dropdown with brands 
      public int BrandId { get; set; }    //The selected value of the dropdown once the form is submitted 
      public string BrandName { get; set; }   //The name of the brand to display in the data-grid List view. 

      //Customer type dropdown 
      [NopResourceDisplayName("Admin.Carts.Fields.CustomerTypeList")] 
      public SelectList CustomerTypeList { get; set; }//The dropdown with CustomerType 
      public int CustomerTypeId { get; set; }   //The selected value of the dropdown once the form is submitted 
      public string CustomerTypeName { get; set; } //The name of the CustomerType to display in the data-grid List view. 

      [NopResourceDisplayName("Admin.Carts.Fields.OpeningDateUtc")] 
      [UIHint("DateNullable")] 
      public DateTime? OpeningDateUtc { get; set; } 

      [NopResourceDisplayName("Admin.Carts.Fields.ClosingDateUtc")] 
      [UIHint("DateNullable")] 
      public DateTime? ClosingDateUtc { get; set; } 

      [NopResourceDisplayName("Admin.Carts.Fields.IsOnline")] 
      public bool IsOnline { get; set; } 

      /* Truncated for relevance */ 
     } 

} 

Vì vậy, cả hai OpeningDateUtcClosingDateUtc là loại DateTime ?.

Đây là cách cơ sở dữ liệu được tạo ra bởi mã EF đầu tiên: EF generated table

Các OpeningDateUtcClosingDateUtc được tạo ra như một lĩnh vực DateTime nullable.

Vậy tại sao nó khi tôi tiết kiệm bằng cách sử dụng IDBContext.SaveChanges(), SQL được tạo ra cho truy vấn là:

exec sp_executesql N'update [dbo].[Cart] 
set [Name] = @0, [ZoneId] = @1, [BrandId] = @2, [CustomerTypeId] = @3, [OpeningDateUtc] = @4, [ClosingDateUtc] = @5, [IsOnline] = @6, [IsReadonly] = @7, [IsPreviewMode] = @8, [CreatedOnUtc] = @9 
where ([Id] = @10) 
',N'@0 nvarchar(100),@1 int,@2 int,@3 int,@4 datetime2(7),@5 datetime2(7),@6 bit,@7 bit,@8 bit,@9 datetime2(7),@10 int',@0=N'Cart1',@1=7,@2=4,@3=5,@4='2013-01-09 00:00:00',@5='2013-01-18 00:00:00',@6=0,@7=0,@8=1,@9='0001-01-01 00:00:00',@10=1 

Phần thú vị là @4 datetime2(7),@5 datetime2(7).

Tôi hiểu rằng tôi có thể khắc phục sự cố này bằng cách thêm .HasColumnType("datetime2") vào bản đồ giỏ hàng nhưng không trả lời tại sao EF5 (và có thể là phiên bản cũ hơn) đặt chúng thành ngày giờ không thể đặt.

Trả lời

15

Loại DateTime trong .NET có cùng phạm vi và độ chính xác như datetime2 trong SQL Server. Khi EF chèn hoặc cập nhật cột datetime hoặc datetime2 trong SQL Server, nó chuyển đổi thuộc tính mô hình thành loại có thể giữ toàn bộ phạm vi DateTime trong .NET, đó là datetime2. Chuyển đổi thành datetime sẽ không thành công nếu thuộc tính DateTime không nằm trong phạm vi datetime trong SQL Server.

Vấn đề gây ra ngoại lệ được, bằng cách này, không phải là hai nullable OpeningDateUtcClosingDateUtc cột, nhưng CreatedOnUtc giá trị đó là '0001-01-01 00:00:00' trong đoạn SQL của bạn, ví dụ: CreatedOnUtc được rõ ràng không được khởi tạo trong tổ chức mô hình của bạn. Ngày sớm nhất mà datetime trong SQL Server có thể lưu trữ là vào năm 1750, vì vậy năm 0001 sẽ không phù hợp với loại (nhưng nó sẽ phù hợp với datetime2).

Vì vậy, giải pháp là đặt CreatedOnUtc thành giá trị datetime hợp lệ hoặc - như bạn đã biết - xác định các loại là datetime2 trong ánh xạ của bạn.

Nhưng tôi đồng ý, sẽ có ít nhầm lẫn hơn nếu EF bản đồ DateTime thuộc tính theo mặc định là datetime2.

+0

Cảm ơn, tôi đã có giải pháp. –

11

Nhóm EF thực sự đã thảo luận về mục cụ thể này trong một trong các cuộc họp thiết kế. Quyết định là để lại hành vi hiện tại như hiện nay. Dưới đây là meeting notes có thể cung cấp cho bạn nhiều ngữ cảnh hơn.

+0

Tuyệt vời đọc, cảm ơn! –

+0

@MattR Cảm ơn thông tin –

Các vấn đề liên quan