将可为空的 DateTime 字段更新为 null 会导致默认 DateTime 值 (0001-01-01 00:00:00.0000000)

Posted

技术标签:

【中文标题】将可为空的 DateTime 字段更新为 null 会导致默认 DateTime 值 (0001-01-01 00:00:00.0000000)【英文标题】:Updating a nullable DateTime field as null results in default DateTime value (0001-01-01 00:00:00.0000000) 【发布时间】:2022-01-01 20:58:14 【问题描述】:

我在我的项目中使用 ASP.NET Boilerplate MVC(非核心)模板,它使用 EF6 作为 ORM。数据库是 SQL Server Express。

这是我的实体对象(忽略不相关的属性):

public class Asset : AggregateRoot<long>

    [DataType(DataType.DateTime)]
    public DateTime? LastControlTime  get; set; 

当我创建一个新资产时,这个字段被适当地创建为 NULL。因此,一切都按照最初的意图进行。但是当我尝试通过简单的服务调用来更新对象时,它就搞砸了。

这是应用服务类中的方法:

public void ResetLastControlTime (EntityDto<long> input)

    var asset = Repository.Get(input.Id);
    asset.LastControlTime = default(DateTime?);

这应该将该字段重置为空。我也试过asset.LastControlTime = null;。但最后它在数据库中的该字段中写入了“0001-01-01 00:00:00.0000000”。我在代码中有很多地方可以控制为空值,所以现在我必须更改大量旧文件,否则我必须找到某种方法将该字段重置为简单的 NULL。

我在这里检查了类似的问题,但找不到答案。所有这些都讲述了我已经拥有的可为空的 DateTime。在 SQL server 表模式中,数据类型是datetime2(7),所以我想这也是正确的。哦,删除 DataType 注释也没有改变任何东西。

那么我在这里错过了什么?我应该检查什么才能发现问题?

【问题讨论】:

日期被转换为它的最小值,可能是因为在这种情况下,日期时间不能为空。也许在这种情况下,请尝试检查DateTime.MinValue 你所有的代码和域模型看起来都是 Nullable,我还没有尝试过,但我猜 default(DateTime?) 在内存中时为 null。我只能想象你没有让实体框架创建你的数据库模式,如果是这样的话,那么也许 SQL 字段设置为 NOT NULL?如果 SQL 模式不能接受 Null,肯定会删除它们。如果您确实让 EF 来创建架构。如果您稍后添加 Nullable,您可能需要 Add-Migration & Update-Database 你有没有试过逐行调试和单步调试代码并观察LastControlTime的值?如果您可以在单步执行代码时在每个点确定 this 的值,那么您应该能够隔离行为不符合预期的确切位置。从我所见,您发布的代码中没有任何内容会导致这种行为,但是您发布的代码中没有任何内容实际上涉及将资产保存到数据库,因此问题可能出在流程的其他地方. @MarkRabjohn 我的数据库是使用 Code First 方法创建的,所以它应该是 EF 创建的。虽然我添加了这一行,但我不记得在 OnModelCreating 方法中添加了这一行:modelBuilder.Properties&lt;DateTime&gt;().Configure(c =&gt; c.HasColumnType("datetime2")); 我不知道这是否与问题有关。顺便说一句,我知道该字段可以为空,因为正如我所说,当创建一个新的 Asset 对象时,日期时间值从 NULL 开始。 @GarethD 好吧,保存部分由 ABP 的工作单元结构 afaik 处理。在应用程序服务方法完成后,它会自动将 C# 对象中所做的更改应用于数据库。虽然我想我可以找到一种方法来查看它发送到服务器的确切 SQL 命令。我可能会在那里捕捉到一些东西(虽然我不确定如何改变它)。 【参考方案1】:

我想如果一切都失败了,您可以通过重新实现该属性来简化大部分代码:

public class Asset : AggregateRoot<long>

    public DateTime? _LastControlTime;
    [DataType(DataType.DateTime)]
    public DateTime? LastControlTime  
      get 
        return _LastControlTime;
      
      set 
        if (value == DateTime.MinValue) 
          _LastControlTime = null;
         else 
          _LastControlTime = value;
        
    

它并没有真正切入问题的核心,但可以让你进步,而无需在整个程序中更改所有 == null 和 .HasValue。

【讨论】:

成功了!因此,问题似乎出在存储库和 ORM 样板代码之间,将空值转换为最小日期时间。我不知道它是什么,但我现在太忙了,无暇顾及。所以,非常感谢您提供这个简单的解决方案。

以上是关于将可为空的 DateTime 字段更新为 null 会导致默认 DateTime 值 (0001-01-01 00:00:00.0000000)的主要内容,如果未能解决你的问题,请参考以下文章

将可为空的 int 映射到可为空的 int + automapper

如何使用 ToString() 格式化可为空的 DateTime?

如何将 C# 可为空的 int 转换为 int

Redshift:sortkey 和 distkey 可以为空吗?

将可为空的列作为参数传递给 Spark SQL UDF

如何从数据库中获取可为空的 DateTime