Отображение NHibernate для Oracle ИНТЕРВАЛ ДЕНЬ ВТОРОЙ тип данных - PullRequest
4 голосов
/ 15 сентября 2011

Не столько вопрос, сколько я бросаю вызов моему коллеге, которого вчера представил администратор базы данных. У нас есть свойство TimeSpan на одном из наших объектов, которое ДОЛЖНО быть сохранено. Да, вы можете просто вывести значение из свойств Start и End DateTime объекта, но администратор базы данных твердо уверен, что это значение будет сохранено в таблице базы данных.

Таким образом, тип данных Oracle, выбранный администратором базы данных для хранения этого значения, - ИНТЕРВАЛЬНЫЙ ДЕНЬ (2) - ВТОРОЙ (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. Знак A также действителен в начале строки, если значение отрицательное. Здесь важно отметить следующее: когда значение отрицательное, каждая часть объекта TimeSpan является отрицательной, если смотреть на нее изолированно, следовательно, не очень красивое «value.Days.ToString (). Contains ('-')» в каждый раздел метода Format ().

Наши тесты пройдены, мы можем сохранить и извлечь значение TimeSpan в столбец базы данных, определенный как INTERVAL DAY (2) TO SECOND (6) через NHibernate.

Если бы кто-то сделал это раньше, мне было бы интересно узнать, как это сделать.

Извините, что не связывал типы Oracle, это мой первый пост, поэтому мне не разрешено ...

1 Ответ

2 голосов
/ 20 сентября 2011
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"/>

Редактировать: добавлен 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; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...