巧合的是,我今天自己也遇到了这个问题 :) 我还没有彻底测试过这个解决方案,而且我是 NHibernate 的新手,但它似乎在我尝试过的微不足道的情况下工作。
首先,您需要创建一个 IUserType 实现,它将从 DateTimeOffset 转换为 DateTime。在 Ayende 博客上有一个关于如何创建用户类型的完整示例,但用于我们目的的相关方法实现是:
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 接口并将其注入到构造函数中。
为了在不修改所有类映射的情况下使用此用户类型,我在 Fluent 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 之间切换。
编辑
根据要求,Fluent 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());
}
}