ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

NHibernate在PostgreSQL 9.0中不断丢失我的DateTime的时区

2019-12-08 00:06:40  阅读:253  来源: 互联网

标签:timezone postgresql nhibernate c


我需要说服NHibernate存储我坚持的DateTime值的时区.列是带有时区的时间戳.

我们有一个约定,我们只将UTC DateTimes存储在数据库中,因此我们使用没有时区的时间戳,但是我需要数据库代表知道时区,以便直接访问数据库的报表能够正确执行.

我试着告诉NHibernate我有DateTime的自定义类型,如下所示:

    [Serializable]
    public class UtcDateTimeUserType<T> : IUserType
    {
        private static readonly SqlType[] MySqlTypes = {SqlTypeFactory.DateTime };

        public SqlType[] SqlTypes
        {
            get { return MySqlTypes; }
        }

        public System.Type ReturnedType
        {
            get { return typeof(T); }
        }

        public bool IsMutable
        {
            get { return false; }
        }

        public object DeepCopy(object value)
        {
            return value; // DateTime is immutable
        }

        public new bool Equals(object x, object y)
        {
            return object.Equals(x, y);
        }

        public object NullSafeGet(IDataReader resultSet,
                                  string[] names,
                                  object owner)
        {
            int index0 = resultSet.GetOrdinal(names[0]);
            if (resultSet.IsDBNull(index0))
            {
                return null;
            }
            var value = resultSet.GetDateTime(index0);
            return DateTime.SpecifyKind(value, DateTimeKind.Utc);
        }

        public void NullSafeSet(IDbCommand statement,
                                object value,
                                int index)
        {
            if (value == null)
            {
                ((IDbDataParameter)statement.Parameters[index]).Value = DBNull.Value;
            }
            else
            {
                var dateTime = (DateTime)value;
                if (dateTime == DateTime.MinValue) dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);
                if (dateTime.Kind == DateTimeKind.Unspecified)
                    throw new InvalidOperationException(
                        "Attempting to save a datetime without a Kind set.. what time zone are you in?");
                ((IDbDataParameter) statement.Parameters[index]).Value = dateTime.ToUniversalTime();

            }
        }

        public object Disassemble(object value)
        {
            return value;
        }

        public object Assemble(object cached, Object owner)
        {
            return cached;
        }

        public object Replace(object original, object target, object owner)
        {
            return original;
        }

        public int GetHashCode(Object x)
        {
            return x.GetHashCode();
        }
    }

    public class NullableUtcDateTimeUserTypeConvention
  : UserTypeConvention<UtcDateTimeUserType<DateTime?>>
    {
    }

    public class UtcDateTimeUserTypeConvention
  : UserTypeConvention<UtcDateTimeUserType<DateTime>>
    {
    }

流利的NHibernateConfiguration

    autoPersistenceModel = autoPersistenceModel.Conventions.Setup(s =>
                               {
                                   s.Add<TableNameConvention>();
                                   s.Add<PrimaryKeyConvention>();
                                   s.Add<CustomForeignKeyConvention>();
                                   s.Add<CascadeConvention>();
                                   s.Add<CalculatedFieldPropertyConvention>();
                                   s.Add<UtcDateTimeUserTypeConvention>();
                                   s.Add<NullableUtcDateTimeUserTypeConvention>();
                                   s.AddAssembly(assembly);
                               });

这捕获了尝试在未设置时区的情况下保留日期时间的代码.它还可以确保所有DateTimes在进入数据库之前都是UTC,并在返回时将其正确设置为UTC.

但是以下语句不起作用:

((IDbDataParameter) statement.Parameters[index]).Value = dateTime.ToUniversalTime();

分配后仍未指定:

((DateTime)((IDbDataParameter) statement.Parameters[index]).Value).Kind

我从NHibernate的代码中注意到PostgresDialect具有以下内容:

 RegisterColumnType(DbType.DateTime, "timestamp");

但没有提及带时区或timestamptz的时间戳.

如何使NHibernate将带有时区的DateTimes保留到Postgres9中?

解决方法:

NpgSQL驱动程序似乎有一个错误:

赋值(((IDbDataParameter)statement.Parameters [index]).Value = dateTime.ToUniversalTime();调用Value属性上的set.这会将DateTime转换为NpgsqlTimeStamp并将其存储,然后将其转换回System.DatetTime并将其存储在值中.

问题在于它使用的是NpgsqlTimeStamp而不是NpgsqlTimeStampTZ,因此丢失了时区信息.

标签:timezone,postgresql,nhibernate,c
来源: https://codeday.me/bug/20191207/2087548.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有