2013-01-09 8 views
7

Zapisuję obiekt koszyka do bazy danych, która ma zerową wartość zerową. Jest to błąd otrzymuję:Dlaczego kod EF5 po raz pierwszy używa datetime2 podczas wstawiania zerowalnej datetime do bazy danych?

Konwersję datetime2 typu danych na typ danych datetime spowodowało wartości out-of-zakresu.

Istnieje sporo postów stackoverflow dokumentujących poprawki do tego problemu. Jednak, gdy kod tworzy bazę danych, tworzy ją jako DateTime (dopuszcza wartości zerowe). Ale z jakiegoś powodu kod próbuje najpierw wstawić za pomocą pola DateTime2.

Zastanawiam się, dlaczego EF tworzy pole w jedną stronę, ale wstawia za pomocą innego typu dla tego samego pola.

Jest to obiekt domeny:

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 */ 
    }  
} 

Model:

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 */ 
     } 

} 

więc zarówno OpeningDateUtc a ClosingDateUtc są typu DateTime ?.

ten sposób baza danych zostanie wygenerowany przez pierwszego kodu EF: EF generated table

OpeningDateUtc i ClosingDateUtc tworzone są jako wartości pustych polu DateTime.

Więc dlaczego jest to, kiedy zaoszczędzić używając IDBContext.SaveChanges(), SQL generowany jest dla zapytania:

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 

Interesującą częścią bycia @4 datetime2(7),@5 datetime2(7).

Rozumiem, że mogę rozwiązać ten problem, dodając do mapy koszyka .HasColumnType("datetime2"), ale nie odpowiada, dlaczego EF5 (i prawdopodobnie starsze wersje) ustawiają je na zerowalną wartość datetime.

Odpowiedz

15

Typ DateTime w .NET ma taki sam zakres i precyzję, co datetime2 w SQL Server. Kiedy EF wstawia lub aktualizuje kolumnę datetime lub datetime2 w SQL Server konwertuje właściwość modelu do typu, który może pomieścić całą gamę DateTime w .NET, to datetime2. Konwersja na datetime zakończy się niepowodzeniem, jeśli właściwość DateTime nie znajduje się w zakresie od datetime w SQL Server.

Problem, który powoduje Wyjątkiem są, nawiasem mówiąc, nie dwa i ClosingDateUtcOpeningDateUtc dopuszczające wartość null kolumn, ale wartość CreatedOnUtc który jest '0001-01-01 00:00:00' w SQL fragmencie, tj CreatedOnUtc najwyraźniej nie zainicjowany w swojej jednostce modelu. Najwcześniejsza data zapisania datetime w SQL Server to rok 1750, więc rok 0001 nie będzie pasował do typu (ale będzie pasował do datetime2).

Rozwiązaniem jest ustawienie wartości CreatedOnUtc na prawidłową wartość datetime lub - jak wiadomo - zdefiniowanie typów jako datetime2 w mapowaniu.

Ale zgadzam się, mniej byłoby nieporozumień, gdyby EF domyślnie zamapowało na domy DateTime na datetime2.

+0

Dzięki, mam rozwiązanie. –

11

Zespół EF faktycznie omawiał ten konkretny przedmiot podczas jednego ze spotkań projektowych. Decyzja polegała na pozostawieniu obecnego zachowania tak, jak jest. Oto meeting notes, które mogą dać ci więcej kontekstu.

+0

Doskonała lektura, dzięki! –

+0

@MattR Dzięki za informację –

Powiązane problemy