ChatGPT解决这个技术问题 Extra ChatGPT

将 datetime2 数据类型转换为 datetime 数据类型会导致值超出范围

我有一个包含 5 列的数据表,其中一行被数据填充,然后通过事务保存到数据库中。

保存时,返回错误:

将 datetime2 数据类型转换为 datetime 数据类型导致值超出范围

这意味着,如阅读,我的数据表的类型是 DateTime2,我的数据库是 DateTime;那是错的。

日期列设置为 DateTime,如下所示:

new DataColumn("myDate", Type.GetType("System.DateTime"))

问题

这可以在代码中解决还是必须在数据库级别进行更改?


J
John Zabroski

简答

如果您未将值初始化为 DateTime 字段,则可能会发生这种情况;该字段不接受 NULL 值,它是一个值类型,因此将使用不可为空的 DateTime 类型的默认值。

设置值为我修复了它!

长答案

default(DateTime) 的值为 DateTime.MinValue(或 new DateTime(1, 1, 1) 或 01/01/0001),它不是有效的 SQL datetime 值。

由于使用公历,SQL Server 日期时间的最低有效值为 01/01/1753。但是,SQL Server DateTime2 支持从 01/01/0001 开始的日期。默认情况下,实体框架使用 DateTime2 来表示日期,因此生成的 SQL 会隐式地将生成的 DateTime2 值强制转换为 SQL Server 端的 DateTime 值。


在实体框架中,如果您添加一个非空的 Created 列,然后更新您的 EDMX,当您没有在代码中设置值时,可能会以这种方式抛出此错误
是什么为你解决的?当您有一个将 getdate() 调用作为默认值的日期时间字段时,会出现此错误。
为什么实体框架不能忽略如果 NULL,因为在我的 SQL 端,我有一个默认值 = getdate()?
我相信它发生的是 EntityFramework 看到一个 DateTime.MinValue ,它是 0001 年并且在 SQL 中 datetime 超出了范围值,因此它将这个值作为 DateTime2 (支持 0001 年)值发送,因此插入/更新是有效的,但是当 SQL 尝试将此 DateTime2 转换为 DateTime 时,它会失败,因为这将导致不同的值。两种解决方案是:1 在模型中使用可为空的日期时间或 2. 在保存上下文更改之前将所有日期时间值初始化为正确的值。您做出的选择取决于日期时间在您的模型中的含义。
@GuillermoRuffino 的解决方案对我有用。检查所有字段并找到那些 0001 年的条目。
S
SharpC

DATETIMEDATETIME2 都映射到 .NET 中的 System.DateTime - 您不能真正进行“转换”,因为它实际上是相同的 .NET 类型。

请参阅 MSDN 文档页面:http://msdn.microsoft.com/en-us/library/bb675168.aspx

这两个的“SqlDbType”有两个不同的值 - 您可以在 DataColumn 定义中指定这些值吗?

但是:在 SQL Server 上,支持的日期范围完全不同。

DATETIME 支持 1753/1/1 到“永恒”(9999/12/31),而 DATETIME2 支持 0001/1/1 到永恒。

因此,您真正需要做的是检查日期的年份 - 如果它在 1753 年之前,您需要将其更改为 1753 年之后的值,以便 SQL Server 中的 DATETIME 列处理它。

马克


这解释了我遇到的问题。虽然很少有情况需要处理 1753/1/1 之前的实际日期,但在很多情况下获取默认值 0001/1/1 可能会导致错误。
我确认当我尝试将 'new DateTime()' 插入到 'datetime' 数据类型时,我收到了这个异常。
我试图在写入数据库的 C# 代码中分配 DateTime.MinValue 的默认值。这解释了我遇到的错误。 +1
我使用 Entity Framework Code First 并使用具有 DateTime 属性的模型。 DtInit = new System.DateTime(1492, 10, 12), 失败。
这是真正原因隐藏在补丁后面的情况之一...... +1
m
marc_s

在我的 SQL Server 2008 数据库中,我将 DateTime 列标记为不可为空,但将 GetDate() 函数作为其默认值。使用 EF4 插入新对象时,我收到此错误,因为我没有明确传递对象上的 DateTime 属性。我希望 SQL 函数为我处理日期,但它没有。我的解决方案是从代码中发送日期值,而不是依赖数据库来生成它。

obj.DateProperty = DateTime.now; // C#

乐意效劳。这很烦人,因为您认为 EF 数据上下文能够在从表中创建对象时发现该字段具有默认值。
我会想很多关于 EF 的事情。我正在使用 POCO 自我跟踪实体,它就是这样一个集群。我将检查代码优先模型,如果这也充满废话,我正在认真考虑回到 linq to sql 并使用对象映射器将道具映射到我自己的实体......
两周前,我在 VS Live 上看到了 EF Code First 的演示,它看起来很棒,顺便说一句。
那是好消息。我们很快将在我的办公室启动一个新项目,我在 EF-CF 和 dapper(由 SO 使用/维护)方面存在分歧。它可能会归结为在通过 WCF 服务使用的应用程序中哪个更好。
你好,岁的评论!我自己从 EF Code-First 开始,发现在我的 POCO 上我只需要将我的 datetime 成员定义为 Nullable<DateTime>,在代码中我可以将其保留为空(而不是 01/01/0000)。我很惊喜地看到 EF 到 SQL 知道在 INSERT 上忽略这个 null 并使用来自服务器的日期 (GetDate())... 对我们来说这甚至更可取,因为我们需要在服务器上更好的一致性,而不用担心webserver 和 sql server 之间的时钟差异。
J
JGilmartin

对我来说,这是因为日期时间是..

01/01/0001 00:00:00

在这种情况下,您想将 null 分配给您的 EF DateTime 对象...以我的 FirstYearRegistered 代码为例

DateTime FirstYearRegistered = Convert.ToDateTime(Collection["FirstYearRegistered"]);
if (FirstYearRegistered != DateTime.MinValue)
{
    vehicleData.DateFirstReg = FirstYearRegistered;
}  

我正在使用 ExcelDataReader 解析此数据,当输入无效文本时它返回 01/01/0001(不会按预期抛出异常 - 使用 .GetDateTime(columnIndex) 方法)。与 MinValue 的比较起到了防止 sql 中超出范围异常的作用。
m
marc_s

这让我快疯了。我想避免使用可为空的日期时间 (DateTime?)。我也没有使用 SQL Server 2008 的 datetime2 类型的选项

modelBuilder.Entity<MyEntity>().Property(e => e.MyDateColumn).HasColumnType("datetime2");

我最终选择了以下:

public class MyDb : DbContext
{
    public override int SaveChanges()
    {
        UpdateDates();
        return base.SaveChanges();
    }

    private void UpdateDates()
    {
        foreach (var change in ChangeTracker.Entries<MyEntityBaseClass>())
        {
            var values = change.CurrentValues;
            foreach (var name in values.PropertyNames)
            {
                var value = values[name];
                if (value is DateTime)
                {
                    var date = (DateTime)value;
                    if (date < SqlDateTime.MinValue.Value)
                    {
                        values[name] = SqlDateTime.MinValue.Value;
                    }
                    else if (date > SqlDateTime.MaxValue.Value)
                    {
                        values[name] = SqlDateTime.MaxValue.Value;
                    }
                }
            }
        }
    }
}

使用 [Column(TypeName = "datetime2")]
Ω
ΩmegaMan

有时 EF 不知道正在处理计算列或触发器。按照设计,这些操作将在插入后在 EF 之外设置一个值。

修复方法是在 EF 的 edmx 中为 StoreGeneratedPattern 属性中的该列指定 Computed

对我来说,当列有一个插入当前日期和时间的触发器时,请参见下面的第三部分。

解决步骤

在 Visual Studio 中打开 Model Browser 页面,然后打开 Model,然后打开 Entity Types ->然后

选择实体和日期时间属性 Select StoreGeneratedPattern Set to Computed

https://i.stack.imgur.com/EOSuR.png

对于这种情况,其他答案是解决方法,该列的目的是在创建记录时指定时间/日期,这是 SQL 执行触发器以添加正确时间的工作。比如这个 SQL 触发器:

DEFAULT (GETDATE()) FOR [DateCreated]


请注意,我使用了 GETDATE(),我当时确实这样做了。但是最近有一条评论说,我认为应该将 SYSDATETIME() 用于任何 DateTime2 操作。
K
Kiquenet

我遇到了这个并将以下内容添加到我的 datetime 属性中:

 [Column(TypeName = "datetime2")]
 public DateTime? NullableDateTimePropUtc { get; set; }

using System.ComponentModel.DataAnnotations.Schema; 必填
L
Lijo

如果我们不传递日期时间字段,则默认日期 {1/1/0001 12:00:00 AM} 将被传递。

但是此日期与实体框架不兼容,因此它会将 datetime2 数据类型转换为 datetime 数据类型导致超出范围的值

如果您没有传递任何日期,只需 default DateTime.now 到日期字段。

movie.DateAdded = System.DateTime.Now

我会说将“DateTime.Now”作为默认值传递远非正确,而且相当具有误导性。
R
Rob Farley

最简单的方法是将数据库更改为使用 datetime2 而不是 datetime。兼容性很好,你不会得到你的错误。

你仍然想做一堆测试......

该错误可能是因为您尝试将日期设置为 0 年或其他内容 - 但这完全取决于您可以控制更改内容的位置。


s
stink

我发现这篇文章试图弄清楚为什么我不断收到以下错误,其他答案对此进行了解释。

将 datetime2 数据类型转换为 datetime 数据类型导致值超出范围。

使用可为空的 DateTime 对象。公共日期时间?购买日期 { 得到;放; }

如果您使用实体框架 将 edmx 文件中的可为空属性设置为 True

https://i.stack.imgur.com/JCCA3.png


C
Community

正如 andyuk 已经指出的,当将 NULL 值分配给不可为空的 DateTime 字段时,可能会发生这种情况。考虑将 DateTime 更改为 DateTime?Nullable<DateTime>。请记住,如果您使用 Dependency Property,还应确保您的依赖项属性的类型也是可为空的 DateTime 类型。

下面是一个不完整的 DateTime 到 DateTime 的真实示例?引发奇怪行为的类型调整

https://i.stack.imgur.com/2lR6K.png


M
Mahmut C

Entity Framework 4 使用 datetime2 数据类型,因此在 db 中,对于 SQL Server 2008,相应的字段必须是 datetime2。

要获得解决方案,有两种方法。

要在实体框架 4 中使用日期时间数据类型,您必须将 edmx 文件中的 ProviderManifestToken 切换为“2005”。如果您将相应的字段设置为 Allow Null(它将其转换为 NULLABLE),那么 EF 会自动将日期对象用作日期时间。


对于我的数据库模型(POCO 类),我了解了您的第二点,并想知道如何将字段设置为可为空的类型。如果有人想知道,您可以通过在日期类型后添加问号 (?) 来做到这一点。例如公共日期时间?开始时间 { 得到;放;这为我解决了这个问题。我唯一需要做的就是在一行代码周围放置一个 TimeSpan 强制转换,在该代码行中我将两个可以为空的 DateTime 值相减。例如 var timeTaken = (TimeSpan) (endTime - startTime);
c
colidyre

在模型类的属性上添加下面提到的属性。

Attribute = [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
Reference = System.ComponentModel.DataAnnotations.Schema

最初我忘了添加这个属性。所以在我的数据库中,约束的创建就像

ALTER TABLE [dbo].[TableName] ADD DEFAULT (getdate()) FOR [ColumnName]

我添加了这个属性并更新了我的数据库然后它变成了

ALTER TABLE [dbo].[TableName] ADD CONSTRAINT [DF_dbo.TableName_ColumnName] DEFAULT (getdate()) FOR [ColumnName]

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
d
dynamiclynk

基于@sky-dev 实现创建了一个基类。所以这可以很容易地应用于多个上下文和实体。

public abstract class BaseDbContext<TEntity> : DbContext where TEntity : class
{
    public BaseDbContext(string connectionString)
        : base(connectionString)
    {
    }
    public override int SaveChanges()
    {

        UpdateDates();
        return base.SaveChanges();
    }

    private void UpdateDates()
    {
        foreach (var change in ChangeTracker.Entries<TEntity>())
        {
            var values = change.CurrentValues;
            foreach (var name in values.PropertyNames)
            {
                var value = values[name];
                if (value is DateTime)
                {
                    var date = (DateTime)value;
                    if (date < SqlDateTime.MinValue.Value)
                    {
                        values[name] = SqlDateTime.MinValue.Value;
                    }
                    else if (date > SqlDateTime.MaxValue.Value)
                    {
                        values[name] = SqlDateTime.MaxValue.Value;
                    }
                }
            }
        }
    }
}

用法:

public class MyContext: BaseDbContext<MyEntities>
{

    /// <summary>
    /// Initializes a new instance of the <see cref="MyContext"/> class.
    /// </summary>
    public MyContext()
        : base("name=MyConnectionString")
    {
    }
    /// <summary>
    /// Initializes a new instance of the <see cref="MyContext"/> class.
    /// </summary>
    /// <param name="connectionString">The connection string.</param>
    public MyContext(string connectionString)
        : base(connectionString)
    {
    }

     //DBcontext class body here (methods, overrides, etc.)
 }

D
David Alan Condit

我在一个简单的控制台应用程序项目中遇到了这个问题,我的快速解决方案是通过运行此方法将任何可能的 datetime2 日期转换为可为空的日期时间:

static DateTime? ParseDateTime2(DateTime? date)
    {
        if (date == null || date.ToString() == "1/1/0001 12:00:00 AM")
        {
            return null;
        }
        else
        {
            return date;
        }
    }

这当然不是一个完全全面的方法,但它可以满足我的需求,也许它会帮助其他人!


这帮助我意识到我的审计功能没有在我的模型上运行,因为没有触及默认日期值。这可能不是答案的预期用途,但它是震撼我的线索。 DateTime 的默认值在插入时超出范围。回顾一下,我只是忘记在我们的模型类上实现一个审计信息接口......经过漫长的一天可能很难找到......
M
Mukhtiar Zamin

在我的情况下,当为 Nullable DateTime 列显式分配 NULL 值时,然后您尝试保存更改。会弹出这个错误。


C
Community

在我的例子中,我们将一个日期转换为一个日期时间,我们得到了这个错误。 What happens is that Date has a "more programmer oriented" minimum of 01/01/0001, while Datetime is stuck at 1753

将它与我们的数据收集错误结合起来,您就会得到例外!


America Discover 1492,如果不使用 datetime2 则错误
J
Jaime Enrique Espinosa Reyes

有时它在开发机器上运行良好,而不是在服务器上运行良好。就我而言,我不得不说:

<globalization uiCulture="es" culture="es-CO" />

在 web.config 文件中。

机器(服务器)中的时区是正确的(对于 CO 区域设置),但 Web 应用程序没有。此设置完成,并且再次正常工作。

当然,所有日期都有价值。

:D


H
Howie Krauth

将此代码添加到 ASP.NET 中的类对我有用:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
}

m
marcolomew

我知道这个问题,你们也应该是:

https://en.wikipedia.org/wiki/Year_2038_problem

在 SQL 中创建了一个新的字段类型来避免这个问题 (datetime2)。

此“日期”字段类型具有与 DateTime .Net 类相同的范围值。它会解决你所有的问题,所以我认为解决它的最好方法是改变你的数据库列类型(它不会影响你的表数据)。


R
RainyTears

检查以下两个:1)该字段没有NULL值。例如:

 public DateTime MyDate { get; set; }

替换为:

public DateTime MyDate { get; set; }=DateTime.Now;

2) 再次新建数据库。例如:

db=new MyDb();

如果您不希望该值默认为 DateTime.Now 怎么办?
如果您不想:DateTime.Now。您可以使用: new DateTime(... , ... , ...)
F
FrankyHollywood

继承日期时间属性的问题

当不可为空的日期字段在插入/更新时的值为 null 时,通常会显示此错误消息。一个原因可能是继承。

如果您的日期是从基类继承的并且您没有进行映射,则 EF 将不会读取它的值。

有关详细信息:https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and-choosing-strategy-guidelines


m
mp3846

当我想编辑一个使用 ASP.Net MVC 的页面时,我看到了这个错误。创建时我没有问题,但更新数据库使我的 DateCreated 属性超出范围!

如果您不希望您的 DateTime 属性为 Nullable 并且不想检查其值是否在 sql DateTime 范围内(并且 @Html.HiddenFor 没有帮助!),只需在相关类中添加一个 static DateTime 字段(控制器)并在 GET 运行时为其赋值,然后在 POST 运行时使用它:

public class PagesController : Controller
{
    static DateTime dateTimeField;
    UnitOfWork db = new UnitOfWork();

    // GET:
    public ActionResult Edit(int? id)
    {
        Page page = db.pageRepository.GetById(id);
        dateTimeField = page.DateCreated;
        return View(page);
    }

    // POST: 
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(Page page)
    {
        page.DateCreated = dateTimeField;
        db.pageRepository.Update(page);
        db.Save();
        return RedirectToAction("Index");

    }
}

C
Conrado Fonseca

检查数据库中的请求格式。例如我的数据库有默认值或绑定 (((1)/(1))/(1900))

System.DateTime MyDate = new System.DateTime( 1900 ,1, 1);

https://i.stack.imgur.com/J3a9Z.png


J
Jitka Darbie Hübnerová

对我来说,我有一个 Devexpress DateEdit 组件,它通过 Nullable 模型属性绑定到可为空的日期时间 MSSQL 列。我所要做的就是在 DateEdit 上设置 AllowNullInput = True。将其设置为“默认”会导致日期 1.1.0001 出现 - 仅在离开 DateEdit 之前 - 然后由于上述后续说明,我收到了此转换错误消息。


m
mikeytown2

对于代码优先上下文:

从此走

    public DateTime Created { get; set; }

对此。添加 [DatabaseGenerated(DatabaseGeneratedOption.Computed)] 属性。

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime Created { get; set; }

在你的模型中。

确保也将其添加到顶部

using System.ComponentModel.DataAnnotations.Schema;

K
Koteshwar

您将拥有日期列,该列设置为小于允许的 dattime 的最小值,例如 1/1/1001。

为了克服这个问题,您可以为您的属性设置正确的日期时间值,还可以设置另一个神奇的属性,例如 IsSpecified=true。