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

Posted

技术标签:

【中文标题】将 datetime2 数据类型转换为 datetime 数据类型会导致值超出范围【英文标题】:Conversion of a datetime2 data type to a datetime data type results out-of-range value 【发布时间】:2009-08-26 00:39:55 【问题描述】:

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

保存时返回错误:

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

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

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

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

问题

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

【问题讨论】:

【参考方案1】:

如果在字段不接受 NULLDateTime 字段时没有为该字段赋值强>价值观。

这为我解决了问题!

【讨论】:

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

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【参考方案3】:

在我的 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 服务使用的应用程序中哪个更好。 你好,一岁的 cmets!我自己从 EF Code-First 开始,发现在我的 POCO 上我只需要将我的日期时间成员定义为 Nullable<DateTime>,并且在代码中我可以将它真正保留为空(而不是 01/01/0000)。我很惊喜地看到 EF to SQL 知道在 INSERT 上忽略这个 null 并使用来自服务器的日期 (GetDate())... 对我们来说这甚至更可取,因为我们需要更好的服务器一致性,而不用担心webserver 和 sql server 的时钟差异。【参考方案4】:

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

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 中超出范围异常的作用。【参考方案5】:

这个让我发疯。我想避免使用可为空的日期时间 (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")] ?【参考方案6】:

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

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

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


解决步骤

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

    选择实体和日期时间属性 选择StoreGeneratedPattern 设置为Computed


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

DEFAULT (GETDATE()) FOR [DateCreated]

【讨论】:

请注意,我使用了GETDATE(),我当时确实这样做了。但最近有一条评论说,我认为任何 DateTime2 操作都应该使用SYSDATETIME(),我认为这是正确的。【参考方案7】:

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

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

【讨论】:

using System.ComponentModel.DataAnnotations.Schema; 必填【参考方案8】:

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

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

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

movie.DateAdded = System.DateTime.Now

【讨论】:

我会说将 'DateTime.Now' 作为默认值传递远非正确,而且相当具有误导性。【参考方案9】:

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

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

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

【讨论】:

【参考方案10】:

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

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

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

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

【讨论】:

【参考方案11】:

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

以下是不完整的 DateTimeDateTime? 类型调整的真实示例,该调整会引发奇怪的行为

【讨论】:

【参考方案12】:

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);【参考方案13】:

基于@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.)
 

【讨论】:

【参考方案14】:

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

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

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

【讨论】:

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

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

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)]【参考方案16】:

在我的例子中,我们将一个日期转换为一个日期时间,我们得到了这个错误。 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【参考方案17】:

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

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

在 web.config 文件中。

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

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

:D

【讨论】:

【参考方案18】:

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

protected override void OnModelCreating(DbModelBuilder modelBuilder)

    modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));

【讨论】:

【参考方案19】:

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

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

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

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

【讨论】:

【参考方案20】:

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

 public DateTime MyDate  get; set; 

替换为:

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

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

db=new MyDb();

【讨论】:

如果您不希望该值默认为 DateTime.Now 怎么办? 如果你不想:DateTime.Now。您可以使用:new DateTime(... , ... , ...)【参考方案21】:

继承日期时间属性的问题

当不可为空的日期字段在插入/更新时的值为 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

【讨论】:

【参考方案22】:

当我想编辑一个使用 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");

    

【讨论】:

【参考方案23】:

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

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

【讨论】:

【参考方案24】:

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

【讨论】:

【参考方案25】:

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

【讨论】:

【参考方案26】:

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

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

【讨论】:

以上是关于将 datetime2 数据类型转换为 datetime 数据类型会导致值超出范围的主要内容,如果未能解决你的问题,请参考以下文章

将 datetime2 数据类型转换为 datetime 数据错误

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

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

哪一列导致“将 datetime2 数据类型转换为 datetime 数据类型导致值超出范围”?

如何识别列抛出 System.Data.SqlClient.SqlException? (将 datetime2 数据类型转换为 datetime 数据类型)

如何将 sql datetime2 转换为加倍?