您可以創建一個實現既IPreUpdateEventListener
和IPreInsertEventListener
如下一類:
public class InsertUpdateListener : IPreInsertEventListener, IPreUpdateEventListener {
public bool OnPreInsert(PreInsertEvent @event) {
CheckDateTimeWithinSqlRange(@event.Persister, @event.State);
return false;
}
public bool OnPreUpdate(PreUpdateEvent @event) {
CheckDateTimeWithinSqlRange(@event.Persister, @event.State);
return false;
}
private static void CheckDateTimeWithinSqlRange(IEntityPersister persister, IReadOnlyList<object> state) {
var rgnMin = System.Data.SqlTypes.SqlDateTime.MinValue.Value;
// There is a small but relevant difference between DateTime.MaxValue and SqlDateTime.MaxValue.
// DateTime.MaxValue is bigger than SqlDateTime.MaxValue but still within the valid range of
// values for SQL Server. Therefore we test against DateTime.MaxValue and not against
// SqlDateTime.MaxValue. [Manfred, 04jul2017]
//var rgnMax = System.Data.SqlTypes.SqlDateTime.MaxValue.Value;
var rgnMax = DateTime.MaxValue;
for (var i = 0; i < state.Count; i++) {
if (state[i] != null
&& state[i] is DateTime) {
var value = (DateTime)state[i];
if (value < rgnMin /*|| value > rgnMax*/) { // we don't check max as SQL Server is happy with DateTime.MaxValue [Manfred, 04jul2017]
throw new ArgumentOutOfRangeException(persister.PropertyNames[i], value,
$"Property '{persister.PropertyNames[i]}' for class '{persister.EntityName}' must be between {rgnMin:s} and {rgnMax:s} but was {value:s}");
}
}
}
}
}
您還需要在配置會話工廠然後註冊此事件處理程序。在創建NHibernate的會話工廠時,將實例添加到Configuration.EventListeners.PreUpdateEventListeners
和Configuration.EventListeners.PreInsertEventListeners
,然後使用Configuration
對象。
這是幹什麼的:每當NHibernate插入或更新實體時,它將分別調用OnPreInsert()
或OnPreUpdate()
。每種方法都會調用CheckDateTimeWithinSqlRange()
。
CheckDateTimeWithinSqlRange()
遍歷實體的所有屬性值,即對象,正被保存。如果屬性值不爲空,則會檢查它是否爲DateTime
。如果是這種情況,它會檢查它是否不小於SqlDateTime.MinValue.Value
(請注意額外的.Value
以避免例外)。如果您使用的是SQL Server 2012或更高版本,則無需檢查SqlDateTime.MaxValue.Value
。他們會高興地接受,即使是DateTime.MaxValue
,這是幾次大於SqlDateTime.MaxValue.Value
。
如果該值超出允許的範圍,則此代碼將引發帶有適當消息的ArgumentOutOfRangeException
,該消息包含導致問題的類(實體)和屬性的名稱以及傳入的實際值。該消息與SqlDateTime溢出異常的等效SqlServerException
類似,但可以更容易查明問題。
一些事情要考慮。顯然這不是免費的。由於此邏輯消耗CPU,因此會產生運行時間開銷。根據你的情況,這可能不成問題。如果是這樣,您還可以考慮優化此示例中給出的代碼以使其更快。一種選擇可能是使用緩存來避免同一類的循環。另一種選擇可能是僅在測試和開發環境中使用它。對於生產,您可以依靠系統的其他部分正常運行,並且這些值始終在有效範圍內。
另外,請注意,此代碼引入了對SQL Server的依賴關係。 NHibernate通常用於避免這樣的依賴。 NHibernate支持的其他數據庫服務器可能有不同的datetime允許值範圍。同樣,還有解決這個問題的選項,例如通過根據SQL方言使用不同的邊界。
快樂編碼!
請粘貼從應用程序發送到服務器的SQL,如果您沒有nhprof或使用log4net,則可以使用SQL事件探查器 – Rippo 2011-02-01 18:42:05