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

4
我已经覆盖了我的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列,异常没有被抛出,似乎捕获块未被触发。 输入图像描述

1
你没有捕获到它的原因是因为捕获了 DbEntityValidationException 而不是抛出 SqlException。解决方案几乎肯定是这些原因之一:https://dev59.com/YnM_5IYBdhLWcg3wjj0p - StuartLC
谢谢。我能在发布的代码中添加什么内容来获取SqlException的钩子吗?我只是想访问导致异常的属性/字段名称。 - Martin Hansen Lennox
2
令人烦恼的是,据我所知,Sql Server实际上并没有列出罪魁祸首列名。如果您能在执行语句时运行Sql Profiler(或将其粘贴到LinqPad中),则可以获取实际的Sql。但可能的候选是一个未被设置为> 1753(例如作为默认DateTime未初始化)的“DateTime”。 - StuartLC
真是遗憾。啊好吧,知道就好了。你们的评论综合起来对我来说就是答案。如果你们想把它们合并成一个,我可以标记它。 - Martin Hansen Lennox
2个回答

2
TL;DR:
如果您使用 Sql 的 DATETIME 列,请在持久化实体的 .Net DateTime 属性上添加验证,以确保在 SaveChanges() 之前值在 1753 年和 9999 年之间。否则,根据精度要求将 Sql 存储更改为 DATE 或 DATETIME2。
详述:
由于 Sql Server DateTime 数据类型只能存储范围在 1753-9999 年之间的日期,而 .Net DateTime 结构可以存储更大的动态范围和更高的精度,即并非所有的 .Net DateTimes 都可以存储在 Sql Server 的 DATETIME 中。
特别容易出现这种错误的是一个未明确赋值的EF实体上的.Net DateTime属性,因为default(DateTime)0001/01/01
因此,最好根据需要将DATETIME列替换为DATETIME2DATE存储。
结果,在> Sql 2005 RDBMS上,Entity Framework将默认到Sql DATETIME2数据类型,因为这将允许存储超出DATETIME提供的有限范围,并且更接近.Net数据类型。
然而,如果您已经有一个带有 DATETIME 列的现有表格,并且您尝试绑定一个“超出范围”的 DateTime 值,那么令人恼火的是,Sql Server 实际上并没有列出错误的列名。如果您能够在执行语句时运行 Sql Profiler(或将其粘贴到 LinqPad 中),则可以获取实际的 Sql。但是可能的候选项是一个未设置为 > 1753(例如未初始化为默认 DateTime)的 DateTime。
之所以没有捕获到 Exception 是因为 catch DbEntityValidationException 与抛出的 SqlException 之间存在不一致。

1
那批信息比评论还要好 - 非常感谢。 - Martin Hansen Lennox

0

如果我没记错的话,你正在使用MSSQL中的smalldatetime,在某些情况下可能会引发此错误。 请查看this线程以获取答案。

尝试在catch(Exception ex)中捕获,然后您将能够看到确切的错误消息。


我应该在当前的catch子句中再加一个吗?这样我就有一个用于捕获DbEntityValidationException,另一个用于捕获Exception - Martin Hansen Lennox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接