NHibernate的映射为Oracle INTERVAL DAY TO SECOND数据类型 [英] NHibernate mapping for Oracle INTERVAL DAY TO SECOND datatype

查看:255
本文介绍了NHibernate的映射为Oracle INTERVAL DAY TO SECOND数据类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

没有这么多,因为我挑战我的一个同事是$ P $由DBA psented昨天的问题。我们有一个时间跨度的财产我们的对象之一,这已到持久化。是的,你可以只推断出从开始和结束的日期时间属性的对象上,但DBA坚持认为这个值保存在数据库表。

所以由DBA持有的价值选择的Oracle数据类型是INTERVAL DAY(2)TO SECOND(6)。

相应类型的Oracle.DataAccess是OracleDbType.InvervalDS但我没能找到有关如何映射与NHibernate的东西。

我们结束了这个解决方案

 公共类SomeTimeSpanTestClass
    {
        公共虚拟字符串TimeSpanTest {获得;保护套; }
        公共虚拟时间跨度ActualTimeSpan
        {
            得到
            {
                //需要做TimeSpanTest的一些格式可以解析之前
                返回TimeSpan.Parse(TimeSpanTest);
            }
            组
            {
                TimeSpanTest =的String.Format({0} {1} {2} {3} {4} {5},
                    。value.ToString()包含( - )?  - :+,
                    。value.Days.ToString()包含( - )? 。value.Days.ToString()子串(1).PadLeft(2,'0'):value.Days.ToString()PadLeft(2,'0'),
                    。value.Hours.ToString()包含( - )? 。value.Hours.ToString()子串(1).PadLeft(2,'0'):value.Hours.ToString()PadLeft(2,'0'),
                    。value.Minutes.ToString()包含( - )? 。value.Minutes.ToString()子串(1).PadLeft(2,'0'):value.Minutes.ToString()PadLeft(2,'0'),
                    。value.Seconds.ToString()包含( - )? 。value.Seconds.ToString()子串(1).PadLeft(2,'0'):value.Seconds.ToString()PadLeft(2,'0'),
                    。value.Milliseconds.ToString()包含( - )? 。value.Milliseconds.ToString()子串(1).PadLeft(6,'0'):value.Milliseconds.ToString()PadLeft(6,'0')。
                );
            }
        }
    }
 

通过映射为

 <属性名=TimeSpanTest列=TIMESPAN_TEST/>
 

一个非常诺迪测试为

 类节目
    {
        静态无效的主要(字串[] args)
        {
            SomeTimeSpanTestClass spanClass =新SomeTimeSpanTestClass();

            日期时间开始= DateTime.Now;
            日期时间结束= DateTime.Now.AddMinutes(75);
            spanClass.ActualTimeSpan = end.Subtract(开始);

            Console.WriteLine(spanClass.TimeSpanTest);

        }
    }
 

显然,这code未重构以任何方式,但对于这个测试的目的是微不足道呢。

在数据库中的价值主要有看起来像这样+00 01:15:03.000874。甲 - 标记也是在如果值为负的字符串的开始有效。这里要注意的重要一点是:当该值是负的,时间间隔对象的每个部分为负时,在隔离看了,所以就没有那么pretty的value.Days.ToString()包含( - 。 )中的格式()方法的每一个部分。

我们的测试通过,我们能够保存和检索时间跨度值到定义为间隔一天的数据库列(2)TO SECOND(6)通过NHibernate的。

如果任何人有一个更好的方式这样做之前,我会很有兴趣知道怎么办。

道歉不连接的Oracle类型,这是我的第一篇文章,所以我不允许......

解决方案

  public虚拟时间跨度ActualTimeSpan {获得;组; }



类TimeSpanUserType:ImmutableUserType
{
    公众覆盖对象NullSafeGet(IDataReader的RS,字符串[]的名称,对象所有者)
    {
        //需要做TimeSpanTest的一些格式可以解析之前
        返回TimeSpan.Parse((串)RS [名称[0]);
    }

    公众覆盖无效NullSafeSet(IDbCommand的CMD,目标价值,诠释指数)
    {
        VAR时间跨度=(时间跨度)值;
        VAR时间= timespan.Duration();
        VAR timeSpanstring =的String.Format({0} {1} {2} {3} {4} {5},
            (timespan.Ticks℃,)?  - :+,
            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(6,'0'))。

        NHibernateUtil.String.NullSafeSet(CMD,timeSpanstring,索引);
    }

    公众覆盖类型ReturnedType
    {
        {返回的typeof(时间跨度); }
    }

    公众覆盖SQLTYPE []的SQLType
    {
        {返回新的[] {SqlTypeFactory.GetString(8)}; }
    }
}

<属性名=ActualTimeSpan列=TIMESPAN_TESTTYPE =TimeSpanUserType/>
 

编辑:添加immutableUserType

 公共抽象类ImmutableUserType:IUserType
{
    大众新的虚拟布尔等于(对象x,对象Y)
    {
        返回的Object.Equals(X,Y);
    }

    公共虚拟INT GetHash code(对象x)
    {
        返回(X == NULL)? 0:x.GetHash code();
    }

    公众覆盖布尔IsMutable
    {
        获得{返回false; }
    }

    公众覆盖对象的DeepCopy(对象的值)
    {
        返回值;
    }

    公众覆盖对象替换(原始对象,对象的目标,对象所有者)
    {
        回到原来的;
    }

    公众覆盖对象集合(对象缓存,对象所有者)
    {
        返回高速缓存;
    }

    公众覆盖对象拆解(对象的值)
    {
        返回值;
    }

    公共抽象对象NullSafeGet(System.Data.IDataReader RS​​,字符串[]的名称,对象所有者);

    公共抽象无效NullSafeSet(System.Data.IDbCommand CMD,目标价值,诠释指数);
    公共抽象类型ReturnedType {获得; }

    公共抽象SQLTYPE []的SQLType {获得; }
}
 

Not so much a question as I challenge a colleague of mine was presented yesterday by a DBA. We have a TimeSpan property on one of our objects which HAS to be persisted. Yes, you could just infer the value from the Start and End DateTime properties on the object but the DBA is adamant that this value is saved on the database table.

So the Oracle data type chosen by the DBA to hold the value is INTERVAL DAY(2) TO SECOND(6).

The corresponding type in Oracle.DataAccess is OracleDbType.InvervalDS but I've not been able to find anything relating to how to map that with NHibernate.

We ended up with this solution

    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')
                );
            }
        }
    }

With the mapping as

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

A very noddy test as

    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);        

        }
    }

Obviously this code isn't refactored in any way, but for the purpose of this test it's trivial anyway.

The value in the database basically has to look like this "+00 01:15:03.000874". A - sign is also valid at the start of the string if the value is negative. An important point to note here is: when the value is negative, each part of the TimeSpan object is negative when looked at in isolation, hence the not so pretty "value.Days.ToString().Contains('-')" in each section of the Format() method.

Ours tests pass, we are able to save and retrieve a TimeSpan value into a database column defined as INTERVAL DAY(2) TO SECOND(6) via NHibernate.

If anyone has done this before a better way I'd be very interested to know how.

Apologies for not linking the Oracle types, it's my first post so I'm not allowed...

解决方案

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(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"/>

Edit: added 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; }
}

这篇关于NHibernate的映射为Oracle INTERVAL DAY TO SECOND数据类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆