Oracle实体框架提供程序不会储存带有毫秒的DateTime.Now。

6

我基本上和这个人有完全相同的问题。

为什么我无法使用Entity Framework保存当前DateTime.Now

但他使用的是SQL Server,而我使用的是Oracle。(我的应用程序必须与两者兼容)

他的问题在于数据库级别没有正确设置精度。

我注意到,如果我手动编辑Oracle数据库中的毫秒数,EF可以提取带有毫秒的正确时间戳。 但是当我创建一个具有DateTime属性的实体并将其设置为“ DateTime.Now”时,它会被截断。

DateColumn1属性是Oracle类型Timestamp

我记录了插入语句

insert into "SchemaName"."TableName"("DateColumn1") values (:P0) --:P0:'5/14/2015 4:07:27 PM' (Type = Date)

疯狂的是,在SQL Server中这是有效的。


1
DateColumn1 是 Oracle 中的 date 类型列吗?Oracle 的 date 类型有一个时间组件,但只能精确到秒。如果需要获取亚秒级别的精度,你需要使用 timestamp(或 timestamp with time zonetimestamp with local time zone)。 - Justin Cave
@JustinCave。事实证明,我只需要在我的OnModelCreating()方法中添加一些额外的代码,告诉Oracle EF提供程序将该列视为时间戳而不是日期。 - C. Tewalt
3个回答

9

啊哈!我的同事有个绝妙的想法,而且它起作用了!

在我们的 EF 代码中,我们尝试放置:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<EntityClass>().Property(p => p.TIMESTAMP).HasPrecision(6);
}

然后将带有毫秒的DateTime.Now存储到数据库中。

更新 - 值得提及的是我是如何陷入这种困境的

在“测试”应用程序中使用Model First构建数据库

  1. 我的应用程序必须与SQL Server和Oracle一起工作。所以......
  2. 我首先设计了我的EDMX图中的数据库
  3. 完成图后,我生成了SQL Server的DDL。
  4. 由于某种原因,Oracle EF提供程序无法生成DDL,因此我继续手动更改SQL Server DDL,以便在语法上正确

    第一个问题 - 我的Oracle DDL使用了日期而不是时间戳。确保您使用Timestamp!Oracle中的DateTime不会存储毫秒。

使用基于数据库的Code First实现实际解决方案

  1. 我希望该应用程序使用Code First方法(只是我的偏好。我认为它更容易维护)
  2. 因此,我连接到了SQL Server数据库并从该架构生成了所有类。
  3. 我通过了所有单元测试,然后决定在Oracle数据库中进行测试
  4. 即使从DATE更改为Timestamp后,我仍然遇到毫秒进入的问题。
  5. 我在测试Visual Studio解决方案中生成了另一个Code First模型,其中包含Oracle中的TIMESTAMP(6)类型,但是当我查看OnModelCreating代码时,它没有生成任何具有HasPrecision(6)的内容,也没有在生成的C# POCO类中对属性进行任何修饰。
  6. 我注意到,如果在OnModelCreating中使用HasPrecision(6)代码,则Code First的CreateDatabase()实际上会创建一个Oracle TIMESTAMP(6)。如果不这样做,则Oracle EF提供程序将使用DATE

我认为,如果您采用Model First方法,可以在EDMX图中设置精度值,但我听说这是不好的做法。


2
另一个可能的解决方案是在配置类中设置精度。 如果您有这样的实体:

Original Answer

public class MyEntity
    {
        public DateTime? MyDateTimeWithPrecision{ get; set; }
    }

如果您使用以下模型构建器添加配置:

Original Answer翻译成"最初的回答"

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
         modelBuilder.Configurations.Add(new MyEntityConfiguration());
        }

在你的配置类中,你可以按照以下方式进行操作:

然后在您的配置类中,您可以按照以下方式进行操作:

class MyEntityConfiguration : EntityTypeConfiguration<MyEntity>
    {
        public MyEntityConfiguration()
        {
            Property(e => e.MyDateTimeWithPrecision)
                .HasPrecision(6);
         }
     }

使用这种架构方案,您可以为模型中的每个实体拥有一个MyEntityConfiguration类,因此您的代码应该更易读。"Original Answer"翻译成"最初的回答"。

点赞。好主意 - 我同意这会使代码更易读。 - C. Tewalt

1
我想补充一下上面的内容,因为其中有一些让我感到困惑并导致我走了错误的路。日期字段不应该使用TIMESTAMP注释,就像我试图做的那样。您POCO类中的字段应该保持为DateTime:
   public class TimeClass
    {
        public DateTime? StartTime { get; set; }
        public DateTime? StopTime { get; set; }
    }

然后,在每个模型类的每个日期字段上创建模型时,必须设置字段的精度。

     protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema("MySchema"); //see [here][2]

        modelBuilder.Entity<TimeClass>().Property(p => p.StartTime).HasPrecision(6);
        modelBuilder.Entity<TimeClass>().Property(p => p.StopTime).HasPrecision(6);

    }

然后您可以获得毫秒。默认情况下,DateTime字段记录带有秒的时间。

我的 POCO 中的 TIMESTAMP 属性仅仅是属性的名称,.NET 类型仍然是 DateTime。 - C. Tewalt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接