How to prevent NHibernate SqlDateTime overflow when querying the database without using an IUserType?

239 Views Asked by At

Is it possible to prevent this exception when doing an NHibernate Linq query like the following:

var dateFilter = DateTime.Parse("1500-01-01");
return _session.Query<Log>().Where(l => l.Date > dateFilter).ToList();

Result: SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.

I'd like to set the date to the minimum supported date value. I'm already using an Interceptor to do this when inserting and updating the database but I'm looking for a solution to fix Select queries.

public class DataInterceptor : EmptyInterceptor
    {
        public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types)
        {
            DateTimeMinValueToNull(currentState, types);
            return base.OnFlushDirty(entity, id, currentState, previousState, propertyNames, types);
        }

        public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types)
        {
            DateTimeMinValueToNull(state, types);
            return base.OnSave(entity, id, state, propertyNames, types);
        }


        // Prevents the application from crashing when an object's DateTime value is lower than the SQL datetime min value
        private void DateTimeMinValueToNull(object[] state, IType[] types)
        {
            for (int i = 0; i < types.Length; i++)
            {
                if (types[i].ReturnedClass == typeof(DateTime))
                {
                    var value = (DateTime?)state[i];
                    if (value.HasValue && value.Value < (DateTime)SqlDateTime.MinValue)
                    {
                        state[i] = (DateTime)SqlDateTime.MinValue;
                    }
                }
            }
        }
    }
2

There are 2 best solutions below

1
Roman Artiukhin On BEST ANSWER

without using an IUserType

Is this restriction only to avoid changing your mappings?

As in NHibernate 5.2 you can register your custom type as default for all DateTime properties:

//Somewhere before SessionFactory is created
TypeFactory.RegisterType(typeof(DateTime), new YourCustomDateTime(), new[] {"DateTime"});

And with this solution you don't need your current Interceptor.

1
Udontknow On

Which NHibernate version are you using?

With version 5.0.0, there was a breaking change regarding this behaviour (https://github.com/nhibernate/nhibernate-core/blob/5.1.5/releasenotes.txt):

  • The Date NHibernate type will no more replace by null values below its base value (which was year 1753). Its base value is now DateTime.MinValue. Its configuration parameter is obsolete.