具有默认值的 DateTime 的 Fluent NHibernate 映射

Fluent NHibernate mapping for DateTime with default value

我知道有很多关于这个的帖子,我已经阅读了其中的大部分。然而对我来说 有几件事仍然不清楚 并且仍然不起作用。

如果我的数据库架构中有一个 DateTime 类型的字段,并且我想为它分配一个默认值,我会这样做:

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

(不知道是否重要:我正在使用 SQL Server Express 2014。Fluent 配置适用于 SQL Server 2012。)

这在从 ISQL 执行 INSERT 时工作正常,插入记录添加时刻的时间戳。

使用流利的我会写这样的东西:

域:

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

注意:我让 CDate 可以为空!

还有一个像这样的映射 class:

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

在程序中(在我的例子中,这是一个可以从多种类型的程序中调用的库)我做了类似的事情:

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

这总是以 DateTime 溢出异常 结束! (SqlDateTime 溢出。必须在 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM 之间)

似乎没有将值传递给文件 CDate 导致了问题。当我像这样在我的库中添加默认值时:

...
myObj.SomeTextToStore("bla bla bla");
myObj.CDate = DateTime.Now;   // <---- Set the date here
session.SaveOrUpdate(myObj);
...

但这并不是真正的解决方案....

问题:

  1. 我做错了什么/遗漏了什么?
  2. 正确的策略是什么时候 定义默认值?是在数据库上还是在代码中? (什么时候 开始一个普通的新香草项目,我更愿意做 C# 代码中的所有内容,甚至创建和稍后更新架构...)
  3. 关于 域 classes: 创建构造函数是否明智, 用默认值填充字段?

我为字段 CUser 执行此操作,因为在 CUser 中我想添加当前用户上下文

public MyObject()
{
   var o = System.Security.Principal.WindowsIdentity.GetCurrent();
   if (o != null)
   {
       CUser = o.Name;
   }  
}

除了在我的数据库访问层库中用当前日期填充 CDate 字段外,我还可以在域的构造函数中这样做-class 像这样:

public MyObject()
{
   var o = System.Security.Principal.WindowsIdentity.GetCurrent();
   if (o != null)
   {
       CUser = o.Name;
   } 
   CDate = DateTime.Now; 
}

非常感谢您的帮助和意见!

您已将此列定义为数据库中的 NOT NULL 和映射中的 Nullable()。 FluentNHibernate 正在向数据库发送 DbNull,但该数据库被拒绝,因为数据库列不可为空。

您应该决定您的逻辑所在的位置。这是你的代码还是数据库谁做主?

在 FlientNHibernate 中设置默认值已讨论,例如,在 this question

那里的建议代码是:

Map(x => x.SubmitionDate).Default("getdate()").Not.Nullable();

一般来说,我总是建议使用 NHibernate Profiler(付费工具)来查看哪些查询进入了数据库以及它们失败的原因。对优化非常宝贵,你正在使用ORM,现在要小心!

通常对于这种类型的映射,我会在我的映射中执行以下操作:

DynamicInsert();
DynamicUpdate();

这样,如果您在 C# 中有可空类型并且您没有将它们设置为任何内容,nhibernate 将不会将它们包含在插入或更新语句中。当 nhibernate 更新代码中未更改的列时,我从来都不喜欢它。

此外,当您在映射中指定 .Not.Nullable();.Default("getdate()") 时,所有这些都用于模式生成。 nhibernate 实际上并没有使用它来进行任何验证或默认设置。这留给了数据库。