Reputation: 435
I am working on an ASP.NET MVC project with NHibernate as the backend and am having some trouble getting some dates to write back to my SQL Server database tables.
These date fields are NOT nullable, so the many answers here about how to setup nullable datetimes have not helped.
Basically when I try to save the entity which has a DateAdded and a LastUpdated fields, I am getting a SqlDateTime overflow exception. I have had a similar problem in the past where I was trying to write a datetime field into a smalldatetime column, updating the type on the column appeared to fix the problem. My gut feeling is that its going to be some problem with the table definition or some type of incompatible data types, and the overflow exception is a bit of a bum steer.
I have attached an example of the table definition and the query that NHibernate is trying to run, any help or suggestions would be greatly appreciated.
CREATE TABLE [dbo].[CustomPages](
[ID] [uniqueidentifier] NOT NULL,
[StoreID] [uniqueidentifier] NOT NULL,
[DateAdded] [datetime] NOT NULL,
[AddedByID] [uniqueidentifier] NOT NULL,
[LastUpdated] [datetime] NOT NULL,
[LastUpdatedByID] [uniqueidentifier] NOT NULL,
[Title] [nvarchar](150) NOT NULL,
[Term] [nvarchar](150) NOT NULL,
[Content] [ntext] NULL
)
exec sp_executesql N'INSERT INTO CustomPages (Title, Term, Content, LastUpdated, DateAdded, StoreID, LastUpdatedById, AddedById, ID) VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8)',N'@p0
nvarchar(21),@p1 nvarchar(21),@p2 nvarchar(33),@p3 datetime,@p4 datetime,@p5 uniqueidentifier,@p6 uniqueidentifier,@p7 uniqueidentifier,@p8 uniqueidentifier',@p0=N'Size and Colour
Chart',@p1=N'size-and-colour-chart',@p2=N'This is the size and colour chart',@p3=''2009-03-14 14:29:37:000'',@p4=''2009-03-14
14:29:37:000'',@p5='48315F9F-0E00-4654-A2C0-62FB466E529D',@p6='1480221A-605A-4D72-B0E5-E1FE72C5D43C',@p7='1480221A-605A-4D72-B0E5-E1FE72C5D43C',@p8='1E421F9E-9A00-49CF-9180-DCD22FCE7F55'
In response the the answers/comments, I am using Fluent NHibernate and the generated mapping is below
public CustomPageMap() {
WithTable("CustomPages");
Id( x => x.ID, "ID" )
.WithUnsavedValue(Guid.Empty)
. GeneratedBy.Guid();
References(x => x.Store, "StoreID");
Map(x => x.DateAdded, "DateAdded");
References(x => x.AddedBy, "AddedById");
Map(x => x.LastUpdated, "LastUpdated");
References(x => x.LastUpdatedBy, "LastUpdatedById");
Map(x => x.Title, "Title");
Map(x => x.Term, "Term");
Map(x => x.Content, "Content");
}
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false" assembly="MyNamespace.Core" namespace="MyNamespace.Core">
<class name="CustomPage" table="CustomPages" xmlns="urn:nhibernate-mapping-2.2">
<id name="ID" column="ID" type="Guid" unsaved-value="00000000-0000-0000-0000-000000000000"><generator class="guid" /></id>
<property name="Title" column="Title" length="100" type="String"><column name="Title" /></property>
<property name="Term" column="Term" length="100" type="String"><column name="Term" /></property>
<property name="Content" column="Content" length="100" type="String"><column name="Content" /></property>
<property name="LastUpdated" column="LastUpdated" type="DateTime"><column name="LastUpdated" /></property>
<property name="DateAdded" column="DateAdded" type="DateTime"><column name="DateAdded" /></property>
<many-to-one name="Store" column="StoreID" /><many-to-one name="LastUpdatedBy" column="LastUpdatedById" />
<many-to-one name="AddedBy" column="AddedById" /></class></hibernate-mapping>
Upvotes: 5
Views: 7031
Reputation: 449
Actually the reason behind the scene is:
When NHibernate reads the row from the db, the value is null, and that is what the session remembers. When the object is rehydrated by NHibernate the Date is set to the value DateTime.MinValue. When the Session is synchronized with the db, NHibernate assumes that something has changed, because the currentState and the previousState are different and tries to update the row. Which in turn fails, because DateTime.MinValue will not fit into a SqlServer datetime column.
The solution: make your datetime nullable either by putting ? at end of Datetime like DateTime? or Nullable
complet article can be found at: nhibernate-sqldatetime-overflow-issue
Upvotes: 17
Reputation: 612
I faced the same issue table with non nullable datetime columns and a SqlDateTime overflow on a save.
In my case the actual problem was that the save triggered a session.flush which causes an update to some object loaded earlier using the same session. This object did have the 'datetime fields where nullable datetime field should have been used' issue.
In other words: Try to do a session.flush prior to the save or update to check whether the problem is maybe caused by earlier usage of the same session object.
Hope that helps anyone.
Upvotes: 1
Reputation: 1
Just an FYI, I have been working on migrating an existing application to NHibernate from a variety of embedded Data Access approaches. This issue came up quickly, and I found an easy solution that minimized impact to the existing functional application code. Because we are migrating by layer in some cases, the data class interface needed to remain stable if at all possible. The solution here was to continue to use DateTime types for the public interface, add extension methods to the private field types to convert from MinValue to null and back on the private fields in the accessors, and map nHibernate to the private fields.
JF
Upvotes: 0
Reputation: 435
I was using s#architecture/fluentnhibernate to create this mapping, I have upgraded to the latest version and it seems to be working fine.
Upvotes: 0
Reputation: 3535
The SQL script in your question executed just fine on my SQL 2005 installation (once I fixed the quote issues picked up by gbn). And your mapping also looks fine. Sorry to be of so little help.
Upvotes: 0
Reputation: 432261
Why do @p3 and @p4 have 2x single quotes? Copy and paste error?
I can't check (don't have SQL installed here), but should the millisecond separator not be "dot", that is, "2009-03-14 14:29:37.000"
@p3 is "before", @p4 is "after" here:
exec sp_executesql
N'INSERT INTO CustomPages (Title, Term, Content, LastUpdated, DateAdded, StoreID, LastUpdatedById, AddedById, ID)
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8)',
N'@p0 nvarchar(21),@p1 nvarchar(21),@p2 nvarchar(33),@p3 datetime,@p4 datetime,@p5 uniqueidentifier,@p6 uniqueidentifier,@p7 uniqueidentifier,@p8 uniqueidentifier',
@p0=N'Size and Colour Chart',
@p1=N'size-and-colour-chart',
@p2=N'This is the size and colour chart',
@p3=''2009-03-14 14:29:37:000'', --quotes + dot wrong?
@p4='2009-03-14 14:29:37.000', --quotes + dot correct?
@p5='48315F9F-0E00-4654-A2C0-62FB466E529D',
@p6='1480221A-605A-4D72-B0E5-E1FE72C5D43C',
@p7='1480221A-605A-4D72-B0E5-E1FE72C5D43C',
@p8='1E421F9E-9A00-49CF-9180-DCD22FCE7F55'
Upvotes: 0