【问题标题】:NHibernate mapping for Oracle INTERVAL DAY TO SECOND datatypeOracle INTERVAL DAY TO SECOND 数据类型的 NHibernate 映射
【发布时间】:2011-09-15 11:02:38
【问题描述】:

昨天,一位 DBA 提出了一个问题,我质疑我的一位同事。我们的一个对象上有一个TimeSpan 属性,它必须被持久化。是的,您可以从对象的 Start 和 End DateTime 属性推断值,但 DBA 坚持认为该值保存在数据库表中。

因此,DBA 选择保存该值的 Oracle 数据类型是 INTERVAL DAY(2) TO SECOND(6)。

Oracle.DataAccess 中的对应类型是 OracleDbType.InvervalDS,但我无法找到任何与如何使用 NHibernate 进行映射相关的内容。

我们最终得到了这个解决方案

    public class SomeTimeSpanTestClass
    {
        public virtual string TimeSpanTest { get; protected set; }
        public virtual TimeSpan ActualTimeSpan
        {
            get 
            {
                // Need to do some formatting of TimeSpanTest before it can be parsed
                return TimeSpan.Parse(TimeSpanTest);
            }
            set 
            {
                TimeSpanTest = string.Format("{0}{1} {2}:{3}:{4}.{5}",
                    value.ToString().Contains('-') ? "-" : "+",
                    value.Days.ToString().Contains('-') ? value.Days.ToString().Substring(1).PadLeft(2, '0') : value.Days.ToString().PadLeft(2, '0'),
                    value.Hours.ToString().Contains('-') ? value.Hours.ToString().Substring(1).PadLeft(2, '0') : value.Hours.ToString().PadLeft(2, '0'),
                    value.Minutes.ToString().Contains('-') ? value.Minutes.ToString().Substring(1).PadLeft(2, '0') : value.Minutes.ToString().PadLeft(2, '0'),
                    value.Seconds.ToString().Contains('-') ? value.Seconds.ToString().Substring(1).PadLeft(2, '0') : value.Seconds.ToString().PadLeft(2, '0'),
                    value.Milliseconds.ToString().Contains('-') ? value.Milliseconds.ToString().Substring(1).PadLeft(6, '0') : value.Milliseconds.ToString().PadLeft(6, '0')
                );
            }
        }
    }

映射为

    <property name="TimeSpanTest" column="TIMESPAN_TEST"/>

一个非常点头的测试

    class Program
    {
        static void Main(string[] args)
        {
            SomeTimeSpanTestClass spanClass = new SomeTimeSpanTestClass();

            DateTime start = DateTime.Now;
            DateTime end = DateTime.Now.AddMinutes(75);
            spanClass.ActualTimeSpan = end.Subtract(start);

            Console.WriteLine(spanClass.TimeSpanTest);        

        }
    }

显然,这段代码没有以任何方式重构,但对于本次测试而言,它无论如何都是微不足道的。

数据库中的值基本上必须看起来像这样“+00 01:15:03.000874”。如果值为负,则 - 符号在字符串的开头也有效。这里要注意的重要一点是:当值为负时,TimeSpan 对象的每个部分在孤立时都是负的,因此不是那么漂亮的“value.Days.ToString().Contains('-')” Format() 方法的每个部分。

我们的测试通过了,我们能够通过 NHibernate 将 TimeSpan 值保存并检索到定义为 INTERVAL DAY(2) TO SECOND(6) 的数据库列中。

如果有人以前做过更好的方法,我很想知道如何做。

抱歉没有链接 Oracle 类型,这是我的第一篇文章,所以我不允许...

【问题讨论】:

  • 您也可以使用 NH-Usertype 来映射 Timespan-property。然后你不需要 TimeSpanTest 和对象中的转换代码。如果需要,我可以发布一个实现
  • 请。就像我说的,这是我们第一次尝试,如果有更好的方法,我想知道怎么做。

标签: c# .net oracle nhibernate orm


【解决方案1】:
public virtual TimeSpan ActualTimeSpan { get; set; }



class TimeSpanUserType : ImmutableUserType
{
    public override object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        // Need to do some formatting of TimeSpanTest before it can be parsed
        return TimeSpan.Parse((string)rs[names[0]]);
    }

    public override void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        var timespan = (TimeSpan)value;
        var duration = timespan.Duration();
        var timeSpanstring = string.Format("{0}{1} {2}:{3}:{4}.{5}",
            (timespan.Ticks < 0) ? "-" : "+",
            duration.Days.ToString().PadLeft(2, '0'),
            duration.Hours.ToString().PadLeft(2, '0'),
            duration.Minutes.ToString().PadLeft(2, '0'),
            duration.Seconds.ToString().PadLeft(2, '0'),
            duration.Milliseconds.ToString().PadLeft(3, '0').PadRight(6, '0'));

        NHibernateUtil.String.NullSafeSet(cmd, timeSpanstring, index);
    }

    public override Type ReturnedType
    {
        get { return typeof(TimeSpan); }
    }

    public override SqlType[] SqlTypes
    {
        get { return new[] { SqlTypeFactory.GetString(8) }; }
    }
}

<property name="ActualTimeSpan" column="TIMESPAN_TEST" type="TimeSpanUserType"/>

编辑:添加 immutableUserType

public abstract class ImmutableUserType : IUserType
{
    public new virtual bool Equals(object x, object y)
    {
        return object.Equals(x, y);
    }

    public virtual int GetHashCode(object x)
    {
        return (x == null) ? 0 : x.GetHashCode();
    }

    public override bool IsMutable
    {
        get { return false; }
    }

    public override object DeepCopy(object value)
    {
        return value;
    }

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

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

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

    public abstract object NullSafeGet(System.Data.IDataReader rs, string[] names, object owner);

    public abstract void NullSafeSet(System.Data.IDbCommand cmd, object value, int index);
    public abstract Type ReturnedType { get; }

    public abstract SqlType[] SqlTypes { get; }
}

【讨论】:

  • 感谢您的回复。我不确定您如何使用 IDataReader 和 IDbCommand 与 NHibernate 接口。
  • 我不明白这个问题。如代码所示,NH 将它们作为参数提供,您只需插入/检索值
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-10
  • 2011-08-18
相关资源
最近更新 更多