NHibernate中的DateTime精度和NHibernate SchemeExport中对DateTime2的支持

j3f*_*ffb 23 nhibernate datetime timestamp fluent-nhibernate granularity

然后我使用Fluent NHibernate及其自动化功能来映射以下简化的POCO类:

public class Foo
{    
public virtual int Id { get; set; }    
public virtual datetime CreatedDateTime { get; set; }    
}
Run Code Online (Sandbox Code Playgroud)

默认情况下,CreatedDateTime字段将映射到SQL DateTime.但是,如果我进行测试以检查实体是否正确创建,则会失败.这是因为DateTime字段的精度不会保留到SQL数据库.我强调这背后的原因是MS SQL Server DateTime只能通过四舍五入到.000,.003或.007的增量来保持毫秒精度(请参阅http://msdn.microsoft.com/en-us/library /ms187819.aspx).因此,NHibernate在保存到商店时会截断毫秒数.这导致我的测试失败,当检查正确持久的字段,因为我的.NET DateTime保持其毫秒,但在保存已经失去其毫秒之后重新启动DateTime,因此两者不是真正相等.

为了解决这个问题,我将以下映射添加到Foo对象:

public class FooMap : IAutoMappingOverride<Foo>
{
    public void Override(AutoMapping<Foo> mapping)
    {
        mapping.Map(f => f.CreatedDateTime).CustomType("datetime2");     
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道这个映射使得NHibernate将CreatedDateTime持久化为datetime2的SQL类型,它可以存储.NET DateTime可以的完整精度.这是一种享受,现在测试通过了.

然而,一次传递另一个失败:我检查架构导出的测试现在失败,出现以下错误:

System.ArgumentException : Dialect does not support DbType.DateTime2
Parameter name: typecode
Run Code Online (Sandbox Code Playgroud)

堆栈跟踪:

at NHibernate.Dialect.TypeNames.Get(DbType typecode)
at NHibernate.Dialect.Dialect.GetTypeName(SqlType sqlType)
at NHibernate.Mapping.Column.GetDialectTypeName(Dialect dialect, IMapping mapping)
at NHibernate.Mapping.Table.SqlCreateString(Dialect dialect, IMapping p, String defaultCatalog, String defaultSchema)
at NHibernate.Cfg.Configuration.GenerateSchemaCreationScript(Dialect dialect)
at NHibernate.Tool.hbm2ddl.SchemaExport..ctor(Configuration cfg, IDictionary`2 configProperties)
at NHibernate.Tool.hbm2ddl.SchemaExport..ctor(Configuration cfg)
Run Code Online (Sandbox Code Playgroud)

该代码使用NHibernate.Tool.hbm2ddl.SchemaExport对象来调用Execute方法.

我正在使用Fluent v1和NHibernate v2.1.

我也尝试将我映射DateTime到TimeStamp但是甚至无法使映射工作,因为插入失败说明:

无法将显式值插入时间戳列.INSERT与列列表一起使用以排除时间戳列,或将其DEFAULT插入到时间戳列中.

有没有人知道如何让SchemeExport使用datetime2OR如何获取datetime属性的时间戳映射?

Jag*_*uar 32

实际上NHibernate引用声明DateTime nhibernate类型将.NET DateTime存储为在第二级截断的SQL日期时间(没有毫秒粒度)

因此,它提供了TimestampNHibernate类型(type="Timestamp"在映射中),它将.NET DateTime作为SQL 存储datetime而不会截断.这里注意,一个SQL timestamp的数据类型并不需要,如果你有一个以上的将INFACT突破timestamp在一个表中的列.它的区分是这样的重要sql-type,并type在NHibernate的映射属性.

此外,请注意,如果使用过滤器,则在过滤器定义中应用相同的规则:如果指定DateTime参数,则参数的值将被截断而不会超过毫秒.

查看第5.2.2章.基本值类型,表5.3 System.ValueType映射类型.


ael*_*usd 5

对于任何想要实际保留日期的纳秒部分的人,您必须使用DateTime2作为sql-column类型以及Nhibernate DateTime2类型.

这是我设置它的惯例(使用流利)

public class DateTimeConvention : IPropertyConvention, IPropertyConventionAcceptance
{

    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria)
    {
        criteria.Expect(x => x.Type == typeof(DateTime) || x.Type == typeof(DateTime?));
    }
    public void Apply(IPropertyInstance instance)
    {
        instance.CustomSqlType("DateTime2"); //specify that the sql column is DateTime2
        instance.CustomType("DateTime2"); //set the nhib type as well
    }
}
Run Code Online (Sandbox Code Playgroud)

并激活惯例:

 var v = Fluently.Configure()
         .Database(MsSqlConfiguration.MsSql2008
         .ConnectionString(d => d.FromConnectionStringWithKey("connstring"))
         .ShowSql())
         .Mappings(m => m.FluentMappings.AddFromAssemblyOf<IRepository>()
         .Conventions.AddFromAssemblyOf<IRepository>()) //this adds your convention
         .BuildSessionFactory();
Run Code Online (Sandbox Code Playgroud)

使用此功能,您可以在存储日期时保持纳秒.


Jam*_*Ide 1

我在业务课程上的 CreatedDate 审核字段中遇到了同样的问题。我通过使用实用程序方法中的值设置时间来解决这个问题。希望这可以帮助。

     /// <summary>
    /// Return a DateTime with millisecond resolution to be used as the timestamp. This is needed so that DateTime of an existing instance
    /// will equal one that has been persisted and returned from the database. Without this, the times differ due to different resolutions.
    /// </summary>
    /// <returns></returns>
    private DateTime GetTime()
    {
        var now = DateTime.Now;
        var ts = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, now.Millisecond, DateTimeKind.Local);
        return ts;
    }
Run Code Online (Sandbox Code Playgroud)