【问题标题】:Conversion of a datetime2 data type to a datetime data type results out-of-range value将 datetime2 数据类型转换为 datetime 数据类型会导致值超出范围
【发布时间】:2010-11-22 20:08:01
【问题描述】:

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

保存时返回错误:

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

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

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

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

问题

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

【问题讨论】:

    标签: c# sql-server entity-framework datetime orm


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

        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)]
        【解决方案4】:

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

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

        【讨论】:

          【解决方案5】:

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

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

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

          【讨论】:

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

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

          【讨论】:

            【解决方案7】:

            继承日期时间属性的问题

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

            【讨论】:

              【解决方案8】:

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

               public DateTime MyDate { get; set; }
              

              替换为:

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

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

              db=new MyDb();
              

              【讨论】:

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

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

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

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

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

              【讨论】:

                【解决方案10】:

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

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

                【讨论】:

                  【解决方案11】:

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

                  这为我解决了问题!

                  【讨论】:

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

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

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

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


                  解决步骤

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

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


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

                  DEFAULT (GETDATE()) FOR [DateCreated]

                  【讨论】:

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

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

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

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

                  movie.DateAdded = System.DateTime.Now
                  

                  【讨论】:

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

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

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

                  【讨论】:

                  • using System.ComponentModel.DataAnnotations.Schema; 必填
                  【解决方案15】:

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

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

                  【讨论】:

                    【解决方案16】:

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

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

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

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

                    【讨论】:

                      【解决方案17】:

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

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

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

                      【讨论】:

                        【解决方案18】:

                        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
                        【解决方案19】:

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

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

                        【讨论】:

                          【解决方案20】:

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

                          在我的 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&lt;DateTime&gt;,并且在代码中我可以将它真正保留为空(而不是 01/01/0000)。我很惊喜地看到 EF to SQL 知道在 INSERT 上忽略这个 null 并使用来自服务器的日期 (GetDate())... 对我们来说这甚至更可取,因为我们需要更好的服务器一致性,而不用担心webserver 和 sql server 的时钟差异。
                          【解决方案22】:

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

                          【讨论】:

                            【解决方案23】:

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

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

                            在 web.config 文件中。

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

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

                            :D

                            【讨论】:

                              【解决方案24】:

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

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

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

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

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

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

                              【讨论】:

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