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

How to identify column throwing System.Data.SqlClient.SqlException? (conversion of a datetime2 data type to a datetime data type)

我已经覆盖了我的 ApplicationDbContext.SaveChanges() 方法。这通过在黄色和白色错误应用程序错误屏幕上提供立即可见的错误消息来帮助我。

但是当 DateTime 列出现验证错误时,catch 子句似乎没有被激活。

这是为什么?我如何识别无效列?

覆盖方法

public partial class ApplicationDbContext 
{
    public override int SaveChanges()
    {
        try
        {
            return base.SaveChanges();  //**error is thrown here**//
        }
        catch (DbEntityValidationException ex)
        {
            var sb = new StringBuilder();

            foreach (var failure in ex.EntityValidationErrors)
            {
                sb.AppendFormat("{0} failed validation\n", failure.Entry.Entity.GetType());
                foreach (var error in failure.ValidationErrors)
                {
                    sb.AppendFormat("- {0} : {1}", error.PropertyName, error.ErrorMessage);
                    sb.AppendLine();
                }
            }

            throw new DbEntityValidationException(
                "Entity Validation Failed - errors follow:\n" +
                sb.ToString(), ex
                ); 
        }
    }
}

但是 DateTime 列没有抛出异常,似乎 catch 块没有被激活。

如果我没记错的话,您在 MSSQL 中使用的是 smalldatetime,在某些情况下可能会引发此错误。 检查 this 个主题以获取答案。

尝试在 catch(Exception ex) 上查看,您将能够看到确切的错误消息。

TL;DR

  • 如果您使用 Sql DATETIME 列,请向持久化实体上的 .Net DateTime 属性添加验证,以确保值在 17539999 之间之前 .SaveChanges()
  • 否则,根据您的精度要求,将您的 Sql 存储更改为 DATEDATETIME2

详细
鉴于 Sql Server DateTime data type can only store dates in the range 1753 - 9999, whereas the .Net DateTime struct can store a larger dynamic range, and higher precision,即并非所有 .Net DateTimes 都可以存储在 Sql 服务器 DATETIME 中。

特别容易出现此错误的是未明确分配的 EF 实体上的 .Net DateTime 属性,因为 default(DateTime)0001/01/01

因此,优先使用 DATETIME2DATE 存储替换 DATETIME 列。

因此,在 > Sql 2005 RDBMS 上,Entity Framework 将 default 转换为 Sql DATETIME2 数据类型,因为这将允许存储超过DATETIME 提供的有限范围,更接近.Net 数据类型。

但是,如果您确实有一个带有 DATETIME 列的现有 table,并且您 attempt to bind an 'out of band' DateTime value,令人恼火的是,Sql 服务器实际上并没有列出恶意列姓名。如果您在执行语句(或粘贴到 LinqPad)时能够 运行 Sql Profiler,则可以获取实际的 Sql。但可能的候选者是未设置为 > 1753 的 DateTime(例如,被初始化为默认 DateTime)。

你没有抓住 Exception 的原因是 catch DbEntityValidationException 与抛出的 SqlException 之间的脱节。