關於有默認值的字段在用EF做插入操作時的思考


今天在用EF做插入操作的時候發現數據庫中一個datetime類型的字段(CreateDate)的值居然全部為null。於是趕緊看表結構發現CreateDate字段居然是允許為空的。

雖然為空,但是設置了默認值getdate(),按說不應該為null的。於是開始測試。

字段允許Null值的情況

Users表結構如下:

假如一個字段有了默認值,並且又允許為Null,在做插入操作時會發生什么?

如上圖中的表結構,CreateDate是允許為null的,而又有默認值getdate()。這樣在用傳統SQL語句和EF做插入操作時分別會發生什么呢?

先看傳統SQL語句:

insert into Users(Username,Password) values('test','123456')

插入結果:

使用SQL完全沒有問題。

再看使用EF:

Users user = new Users();
user.Username = "test2";
user.Password = "123456";

TestEntities entity = new TestEntities();
entity.Users.Add(user);
int result = entity.SaveChanges();

插入結果:

使用EF插入居然為NULL!!!於是立刻打開SQL Server Profiler監測生成的SQL,EF居然生成了下面的SQL:

沒賦值的字段,EF生成SQL的時候居然都置為NULL,管你有沒有設默認值!

可能是EF比較嬌情,我字段允許為NULL,EF生成SQL時就置為null了。那我把字段設為不允許為NULL,EF又會生成怎樣的SQL呢?

字段不允許Null值的情況

Users表結構如下:

這一次CreateDate不允許為NULL了,使用SQL理所當然地一切正常:

insert into Users(Username,Password) values('admin','123456')

那再看下用EF:

Users user = new Users();
user.Username = "admin";
user.Password = "123456";

TestEntities entity = new TestEntities();
entity.Users.Add(user);
int result = entity.SaveChanges();

結果。。。

”從 datetime2 數據類型到 datetime 數據類型的轉換產生一個超出范圍的值。“

EF很傲嬌地拋了個異常!!為什么會拋出這個異常?這個異常神馬意思?於是照妖鏡SQL Server Profiler又出場了:

日期類型的字段如果不賦值會給默認值“0001-01-01 00:00:00”,這和生成SQL無關,是在生成SQL之前CLR進行的初始化操作,同理String類型的字段如果不賦值會給默認值String.Empty!

但是,那也不至於拋異常啊,頂多字段值存儲為“0001-01-01 00:00:00”唄。

於是查MSDN發現datetime類型的日期范圍僅支持1750-01-01 00:00:00至9999-12-31 23:59:59.997,而0001-01-01 00:00:00不在此范圍內,所以拋出異常。原來如此。

datetime和datetime2支持的日期范圍如下:

結論

如此看來無論字段有沒有默認值,使用EF插入時都沒有任何實際作用了。因此如果你使用EF建議干脆直接寫死算了。比如user.CreateDate = DateTime.Now。

ps.這里只是舉個例子,事實上,在實際項目中不建議寫成DateTime.Now,因為數據庫系統時間和服務器時間一般是不同的,筆者實際項目中其實是封裝了一個方法叫GetSQLServerSystemDateTime。

除此之外是否還有別的方法呢?

方法是有的,打開EF的.edmx文件,找到<EntityType Name="表名">節點,把如下節點:

<Property Name="CreateDate" Type="datetime" Nullable="false"  />

改成:

<Property Name="CreateDate" Type="datetime" Nullable="false" StoreGeneratedPattern="Computed" />

即可。

StoreGeneratedPattern是一個枚舉:
  • None 一個值,指示它不是服務器生成的屬性。這是默認值。如果沒有StoreGeneratedPattern屬性,其值就默認為None。
  • Identity 執行插入時生成一個值,但在執行更新時保持不變。
  • Computed 執行插入和更新時都將生成一個值。

筆者經過實際測試發現:

  1. 如果將StoreGeneratedPattern值設置為Identity,只要一修改CreateDate字段就會拋異常;
  2. 如果把StoreGeneratedPattern值設置為Computed不會拋異常,但值仍然沒有被修改,即使你寫了user.CreateDate = "xxx"。

所以如果你使用EF,我還是建議采用第一種方式,直接在程序中賦值user.CreateDate = xx.GetSQLServerSystemDateTime()。這種方法省事且安全。修改edmx文件太麻煩,況且每增加一個datetime類型的字段都要修改一次edmx文件。

最后感謝大家提出的建議,歡迎大家親自測試並把結果反饋給我。

 

延伸閱讀關於有默認值的字段在用EF做插入操作時的思考(續)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM