巧合的是,我今天自己就碰到了這個問題:)我還沒有徹底地測試過這個解決方案,而且我是NHibernate的新手,但它似乎可以在我嘗試過的微不足道的情況下工作。
首先,您需要創建一個將從DateTimeOffset轉換爲DateTime的IUserType實現。還有如何創建一個用戶類型on the Ayende blog但我們的目的相關方法的實現是一個完整的例子:
public class NormalizedDateTimeUserType : IUserType
{
private readonly TimeZoneInfo databaseTimeZone = TimeZoneInfo.Local;
// Other standard interface implementations omitted ...
public Type ReturnedType
{
get { return typeof(DateTimeOffset); }
}
public SqlType[] SqlTypes
{
get { return new[] { new SqlType(DbType.DateTime) }; }
}
public object NullSafeGet(IDataReader dr, string[] names, object owner)
{
object r = dr[names[0]];
if (r == DBNull.Value)
{
return null;
}
DateTime storedTime = (DateTime)r;
return new DateTimeOffset(storedTime, this.databaseTimeZone.BaseUtcOffset);
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
if (value == null)
{
NHibernateUtil.DateTime.NullSafeSet(cmd, null, index);
}
else
{
DateTimeOffset dateTimeOffset = (DateTimeOffset)value;
DateTime paramVal = dateTimeOffset.ToOffset(this.databaseTimeZone.BaseUtcOffset).DateTime;
IDataParameter parameter = (IDataParameter)cmd.Parameters[index];
parameter.Value = paramVal;
}
}
}
的databaseTimeZone
領域擁有TimeZone
它描述了用於存儲值在數據庫中的時區。在存儲之前,所有DateTimeOffset
值都轉換爲此時區。在我當前的實現中,它被硬編碼到本地時區,但是您可以始終定義一個ITimeZoneProvider接口並將其注入到構造函數中。
要在不改變我所有的類映射使用此用戶類型,我創建了流利的NH公約:
public class NormalizedDateTimeUserTypeConvention : UserTypeConvention<NormalizedDateTimeUserType>
{
}
,我在我的映射應用這個約定,如本例(該new NormalizedDateTimeUserTypeConvention()
是最重要的部分):
mappingConfiguration.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly())
.Conventions.Add(
PrimaryKey.Name.Is(x => x.EntityType.Name + "Id"),
new NormalizedDateTimeUserTypeConvention(),
ForeignKey.EndsWith("Id"));
就像我說的,這是沒有徹底測試,所以要小心!但現在,我需要做的就是修改一行代碼(流暢映射規範),並且可以在數據庫中的DateTime和DateTimeOffset之間切換。
編輯
按照要求,功能NHibernate配置:
要建立SQL Server的一個會話工廠:
private static ISessionFactory CreateSessionFactory(string connectionString)
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionString))
.Mappings(m => MappingHelper.SetupMappingConfiguration(m, false))
.BuildSessionFactory();
}
SQLite的:
return Fluently.Configure()
.Database(SQLiteConfiguration.Standard.InMemory)
.Mappings(m => MappingHelper.SetupMappingConfiguration(m, true))
.ExposeConfiguration(cfg => configuration = cfg)
.BuildSessionFactory();
實施SetupMappingConfiguration的:
public static void SetupMappingConfiguration(MappingConfiguration mappingConfiguration, bool useNormalizedDates)
{
mappingConfiguration.FluentMappings
.AddFromAssembly(Assembly.GetExecutingAssembly())
.Conventions.Add(
PrimaryKey.Name.Is(x => x.EntityType.Name + "Id"),
ForeignKey.EndsWith("Id"));
if (useNormalizedDates)
{
mappingConfiguration.FluentMappings.Conventions.Add(new NormalizedDateTimeUserTypeConvention());
}
}
非常好!現在給出這個鏡頭,可能會稍微改變一下,所以我可以根據上下文注入適當的會話工廠,但是這有希望會讓我走得更遠。在保證我的映射將自己推入SQLite模式方面,有什麼特別需要注意? – bakasan 2010-02-22 03:42:05
我能想到的唯一的事情是(正如我確信你知道的那樣)在SQLite中沒有強制實施FK約束,所以你可能應該有一套在生產平臺上運行的測試。 我目前每個存儲庫都維護兩套測試 - 一種可以針對SQLite運行NHib的東西(級聯,映射等),另一種針對SQL Server運行以測試數據庫的東西(約束等)。 – 2010-02-22 09:58:10
當我嘗試將我的模式應用於內存數據庫時,我似乎遇到了運行時問題 - 您會介意在您建立數據庫選項的位置共享您的Fluent NH配置嗎?錯誤消息基本上是我的方言不支持DateTimeOffset(duh;))..我的數據庫被定義爲數據庫(SQLiteConfiguration.Standard.InMemory()) – bakasan 2010-02-24 07:34:58