Witam
Ostatnio napotkałem na dość ciekawy wyjątek podczas wykonywania NHibernatowego inserta. W bazie danych mam prostą tabelę
Do takiej tabeli został stworzony model
1 2 3 4 5 6 7 8 9 10 |
namespace Model { public class Appointment { public virtual int Id { get; set; } public virtual string Name { get; set; } public virtual DateTime StartDate { get; set; } public virtual TimeSpan Duration { get; set; } } } |
oraz mapping
1 2 3 4 5 6 7 8 9 10 11 12 13 |
namespace Model.Mappings { public class AppointmentMapping : ClassMap<Appointment> { public AppointmentMapping() { Id(val => val.Id).GeneratedBy.Native(); Map(val => val.Name).Not.Nullable(); Map(val => val.StartDate).Not.Nullable(); Map(val => val.Duration).Not.Nullable(); } } } |
Niestety ku mojemu zaskoczeniu próbując zapisać do bazy obiekt typu Appointment dostałem następujący wyjątek
SqlException: Operand type clash: bigint is incompatible with time
Mówiąc szczerze wyjątek ten niewiele mi powiedział, zwłaszcza, że zapytanie wygenerowane przez NHibernata (przechwycone w NHibernateProfilerze) wyglądało jak najbardziej poprawnie. Jednakże zapytanie przechwycone przez SqlProfilera wyglądało w następujący sposób
1 2 3 4 5 6 7 8 |
exec sp_executesql N'INSERT INTO [Appointment] (Name,StartDate,Duration) VALUES (@p0,@p1,@p2); select SCOPE_IDENTITY()', N'@p0 nvarchar(4000), @p1 datetime, @p2 bigint', @p0=N'appoitnemt', @p1='2012-03-13 00:00:00', @p2=439320000000 |
Widać tutaj, że drugi parametr (@p2) został oznaczony jako bigint, a nie time (tak jak jest to oznaczone w bazie). Przyczyną takiego stanu rzeczy jest zły mapping. Z tego co wyczytałem, jeżeli chcemy aby poprawnie zmapować TimeSpana na kolumnę typu time, musimy zmodyfikować interesujący nas mapping na następujący.
1 |
Map(val => val.Duration).Not.Nullable().CustomType("TimeAsTimeSpan"); |
Mając taki mapping nasze zapytanie zostanie wygenerowane poprawnie i operacja insertu zakończy się powodzeniem