|
|
|
I'm thinking about modifying (not really thinking - planning to modify) the DateTimeType, DateType, and TimeType to reflect the standards for DbType
DbType.DateTime A type representing a date and time value. DbType.Date: Date and time data ranging in value from January 1, 1753 to December 31, 9999 to an accuracy of 3.33 milliseconds. DbType.Time: Date and time data ranging in value from January 1, 1753 to December 31, 9999 to an accuracy of 3.33 milliseconds. No - DbType.Date & DbType.Time are not copy mistakes - they are the exact same thing in msdn docs - why??? This will break everyone's (atleast mine) mapping files who relied on DateTime.Min getting converted to null. The only thing that will need to be done is add type="Date" to DateTime properties if MsSql is being used. This is also what the NullableTypes in NHibernateContrib are meant to solve. Any input? Mike I myself think you should allow for all possible DateTime values to be persisted, and let the database handle any errors. Of course this isn't a database-independent solution, but in this case I think it's appropriate.
By the way, what happens when I have a varchar(10) column in the database, mapped to a string property, and try to save an 11-character string? NHibernate doesn't check this either. MySQL silently ignores the last character for example, other databases may be less forgiving. What about just mapping DateTime to DbType.Date or maybe DbType.DateTime and TimeSpan to DbType.Time by default and letting the user adjust the DbType in the mapping file? Oh, and why was DateTime.MinValue converted to null? It doesn't seem to be the case in my copy of NHibernate (but I modified it quite a bit, and MySQL Connector.NET too, so maybe I just didn't notice :-)). Sergey. I think Microsoft's documentation is wrong. Their System.Data.OracleClient assembly has roughly (Reflector) this source for their DateTime type:
---------------8<--------------------- static OracleDateTime() { OracleDateTime.MaxValue = new OracleDateTime(DateTime.MaxValue); OracleDateTime.MinValue = new OracleDateTime(DateTime.MinValue); OracleDateTime.Null = new OracleDateTime(true); } ---------------8<--------------------- I checked the MySQL driver source code, and the only min date check they have is: ---------------8<--------------------- public bool IsValidDateTime { get { return year != 0 && month != 0 && day != 0; } } ... followed by ... public static explicit operator DateTime( MySqlDateTime val ) { if (! val.IsValidDateTime) return DateTime.MinValue; return val.GetDateTime(); } ---------------8<--------------------- Both are roughly respecting the .NET limitations of the DateTime type. I feel that following the MSDN documentation and restricting the minimum value to 1/1/1753 will create confusion. I strongly feel NHibernate should respect the boundaries of the native provider, or the .NET value boundaries if the native driver allows a wider range of values. By having each dialect specify a DateTime property for minimum and maximum values, both boundary exceptions are avoided and developers aren't surprised. We had a hard time finding this bug, knowing that Oracle supports a date < 1/1/1753. It was out of sheer frustration that we tried "what if the Oracle driver was limited the same way as MS SQL Server?". Our jaws dropped when the tests confirmed it. Funny, it's not that we had any data going back that far, but the testers put in the .NET min date value and the app stopped returning data. Oh, to answer a question. The DateTime data type isn't nullable, so an unassigned value will be set to DateTime.MinDate.
For example: public class MinDateTime { private static DateTime birthdate; public static void Main( string[] args ) { Console.WriteLine( birthdate.ToString() ); } } will return "1/1/0001 12:00:00 AM". I kept DateType and TimeType just like they are.
The DateTimeType will no longer magically convert a value before 1753 to null. If that was a relied on feature you should convert the property to a NullableDateTime. To get the most accurate use of System.DateTime use type="Timestamp" - see comments in class TimestampType for why. |
|||||||||||||||||||||||||||||||||||||||
I suspect that many other dialects support different minimum and maximum date values, so IMHO the NHibernate.Type.DateTimeType needs to get those values from the current dialect before using a hard-coded default.
By checking http://www.analysisandsolutions.com/code/dates.htm, I see that MySQL's TIMESTAMP has the highest minimum and both Oracle and PostgreSQL can go back beyond .NET's capability.
I suggest that the NHibernate.Dialect.Dialect class have both a "public virtual DateTime MinDateTime { get; }" and a "public virtual DateTime MaxDateTime { get; }" signature that each dialect should override. This way, the NHibernate.Type.DateTimeType.Set(IDbCommand,object,int) method can call "Dialect.GetDialect().MinDateTime" to get the value to use in line 45.
As the site I referenced points out, some dialects would need to be artificially limited to .NET's DateTime.MinDate and DateTime.MaxDate.
Does that sound like a reasonable solution?