Search code examples
c#sql-servernhibernatefluent-nhibernatelinq-to-nhibernate

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


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

Solution

  • 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.