【问题标题】:SQL DateTime Vs. C# Datetime MinDateSQL 日期时间与。 C# 日期时间 MinDate
【发布时间】:2019-09-06 11:57:11
【问题描述】:

我有一个 SQL Server 数据库,我的一个表LatestData 有一个不可为空的列DATETIME,默认值为01/01/1970。请参阅此列的确切 T-SQL 代码下方的代码。

[MyDateTime] DATETIME DEFAULT (CONVERT([DATETIME], CONVERT([DATE], '1970/01/01 00:00AM', (0)), (0))) NOT NULL

当通过.EDMX 数据模型将此表添加到我们的服务器代码(C#)中时,该字段如下所示:

public System.DateTime MyDateTime { get; set; }

我通过C#向这个表添加了新数据,但是在添加行的时候,我的MyDateTime列没有任何数据。

由于列为Not Null,我的MyDateTime 字段自动设置为01/01/0001

尝试将此日期添加到我的 DateTime 列会引发以下错误:

System.Data.SqlClient.SqlException:将 datetime2 数据类型转换为 datetime 数据类型导致值超出范围。

在做了一些研究后,我发现 C# Datetime MinDate 是 01/01/0001,而 SQL Server DATETIME 的 minDate 是 01/01/1753,这是导致错误的原因。

C# 代码将“空”字段作为01/01/0001 传递给数据库,然后尝试对其进行转换。这显然是不成功的。

数据库有没有办法知道恢复到默认值,而不是先尝试转换DATETIME,或者在转换失败时这样做?

我知道我可以将 Datatable 中的列设置为 DateTime2 或在通过 C# 添加之前为该列指定一个日期,但这似乎不是最好的方法?

提前感谢您的帮助。

【问题讨论】:

  • 使用datetime2 代替日期时间。 C# 中也没有 empty 日期。 DateTime 是一个结构,因此它总是 有一个值。 “零”值为 1/1/001。这不是空的,这是默认的日期值。如果缺少日期,实体属性和数据库列应该可以为空,即DateTime?datetime2(0) NULL。如果不想存储时间,请在数据库中使用date
  • 要么使该字段为空,要么使用docs.microsoft.com/en-us/dotnet/api/…

标签: c# sql-server tsql datetime


【解决方案1】:

如果 1970-01-01 是您可以接受的没有设置日期,则将其放入 C#:

public System.DateTime MyDateTime { get; set; } = new DateTime(1970, 1, 1);

我确实认为你应该考虑在列中允许空值,并做到这一点:

public System.DateTime? MyDateTime { get; set; }

您要求进行仅限 SQLS 的修复;我现在唯一能想到的就是使用存储过程来进行插入:

--set up an example table with a datetime
create table a(a datetime);
--test that an insert doesnt work out
insert into a(a) values(cast('0001-01-01' as datetime2)); --error!
go
--make a procedure to do the insert logic/conversion
CREATE PROCEDURE a_ins(@a DATETIME2) 
AS
BEGIN
  INSERT INTO a (a) 
  --if the date is less than the column will support, default it
  SELECT case when @a < CAST('1753-01-01' as datetime2) THEN cast('1970-01-01' as datetime) else cast(@a as datetime) end
END
GO
--quick run the procedure to test
DECLARE @dt2 DATETIME2 = cast('0001-01-01' as datetime2);
EXEC a_ins @dt2 --inserts 1970

您可以选择要插入的日期范围 - 可能 1970 年之前的任何时间都将成为 1970 年,也可能是 1753 年之前的任何时间,也可能只有 0001-01-01 .. 您在“case when”逻辑中选择

【讨论】:

  • 感谢您的回答 - 在与我的同行交谈后,他们只在数据库/SQL 部分要求修复 - 您知道这是否可能吗?
  • 据我所知,在不改变列类型的情况下,INSTEAD OF 触发器不起作用,因为提供的数据无法加载到要在触发器中使用的虚拟表中, 与它不能加载到主表中的原因相同。不过,您可以创建一个存储过程并让您的 c# 使用它
  • 在帖子中添加了一个存储过程
【解决方案2】:

这是您应该更喜欢 DateTime2 而不是 DateTime 的另一个原因 - DateTime2 数据类型支持与 .Net 框架的 DateTime 结构相同的日期范围 - 从 0001 年 1 月 1 日到 9999 年 12 月 31 日。

MyDateTime数据类型改为DateTime2,默认值改为0001-01-01

ALTER TABLE MyTable
    ALTER COLUMN MyDateTime DateTime2 NOT NULL

要更改默认值约束,您需要删除它并重新创建它。 这可以使用 SSMS 轻松完成(只需找到它,右键单击并拖放),但使用 T-SQL,您将使用 answers from this post 之一,因为您没有指定它的名称。完成后,您可以添加它(这次使用正确的名称):

ALTER TABLE MyTable
    ADD CONSTRAINT DF_MyDateTime DEFAULT ('0001-01-01') FOR MyDateTime 

【讨论】:

    猜你喜欢
    • 2010-12-21
    • 2016-09-19
    • 1970-01-01
    • 2018-01-06
    • 2010-10-22
    • 2011-05-18
    • 1970-01-01
    • 1970-01-01
    • 2012-12-07
    相关资源
    最近更新 更多