I know that there are many threads about this and I have read most of them. However for me a couple of things remain unclear and still do not work.
If I have on my database schema a field of type DateTime and I like to assign it a default value I would do something like this:
create table [mySchema].[MyTable](
ObjectGuid uniqueidentifier CONSTRAINT Id PRIMARY KEY,
SomeTextToStore nvarchar(128) NULL,
CDate datetime NOT NULL DEFAULT GETDATE(),
CUser nvarchar(64) DEFAULT CURRENT_USER
);
GO
(Don't know if it is important: I am using SQL Server Express 2014. Fluent configuration is for SQL Server 2012.)
This works fine when doing an INSERT
from ISQL, inserts a timestamp of the moment when the record was added.
Using fluent I would write something like this:
Domain:
public class MyObject
{
public virtual Guid Id {get; set}
public virtual string SomeTextToStore {get; set;}
public virtual DateTime? CDate {get; set;}
public virtual string CUser {get; set;}
}
NOTE: I made CDate nullable!
And a mapping class like this:
class MyObjectMap : ClassMap<MyObject>
{
public MyObjectMap()
{
Table("MySchema.MyTable");
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.SomeTextToStore).Length(128).Nullable();
Map(x => x.CDate).Not.Nullable().Default("getdate()");
Map(x => x.CUser).Not.Nullable().Default("CURRENT_USER);
}
}
In the program (in my case this is a library that can be called from several type of programs) I do something like:
public void EnterSomeText()
{
using (var session = sessionManager.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var myObj = new MyObject();
myObj.SomeTextToStore("bla bla bla");
session.SaveOrUpdate(myObj);
transaction.Commit();
}
session.Close();
}
}
This ends always in a DateTime overflow exception! (SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM)
It looks like not passing a value to the file CDate
is causing the problem. When I add the default in my library like such it works:
...
myObj.SomeTextToStore("bla bla bla");
myObj.CDate = DateTime.Now; // <---- Set the date here
session.SaveOrUpdate(myObj);
...
But this is not really the solution....
Questions:
I do this for the field CUser
because in CUser
I like to add the current user context
public MyObject()
{
var o = System.Security.Principal.WindowsIdentity.GetCurrent();
if (o != null)
{
CUser = o.Name;
}
}
Instead of filling the CDate field with the current date in my DB-access layer library I could do it also in the constructor of the domain-class like such:
public MyObject()
{
var o = System.Security.Principal.WindowsIdentity.GetCurrent();
if (o != null)
{
CUser = o.Name;
}
CDate = DateTime.Now;
}
Many thanks for your help and comments!
Usually for this type of mapping I do the following in my mapping:
DynamicInsert();
DynamicUpdate();
This way if you have nullable types in C# and you don't set them to anything nhibernate will not include them in the insert or update statement. I never really like it when nhibernate is updating columns that weren't changed in the code anyway.
Furthermore when you specify .Not.Nullable();
and .Default("getdate()")
in the mapping all this is used for is schema generation. It's not actually used by nhibernate to do any validation or defaulting. That is left up to the database.