偶然にも、私は今日この問題に遭遇しました:)私はこのソリューションを完全にテストしていません.NHibernateは初めてですが、私が試した些細なケースではうまくいくようです.
最初に、DateTimeOffset から DateTime に変換する IUserType 実装を作成する必要があります。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"));
私が言ったように、これは完全にテストされていないので、注意してください! しかし今は、1 行のコード (流暢なマッピング仕様) を変更するだけで、データベースで 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());
}
}