将可为空的 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<DateTime>().Configure(c => 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?