DbUpdateException:哪个字段导致"字符串或二进制数据将被截断"

时间:2017-04-13 16:01:18

标签: c# entity-framework exception entity-framework-6

我收到一条带有消息的DbUpdateException

  

字符串或二进制数据将被截断

据我所知,实体中的某个字段不符合数据库中列的长度。而且我可以手动检查它们。

然而,我想要做的是得到一个合理的错误信息,它可能告诉我它实际上是哪个字段!例如。

  

字符串或二进制文件将在字段ProspectName处截断。

我可以打印出很多随机信息。并尝试了各种各样的东西。但没有任何东西指向字段名称。

请注意,DbEntityValidationException类型,它是DbUpdateException

// DbUpdateException exception
foreach (var entry in exception.Entries)
{ 
    builder.AppendLine(String.Format("Error at: Type {0}", entry.Entity.GetType().Name));

    if ((exception.InnerException is System.Data.Entity.Core.UpdateException) &&
        (exception.InnerException.InnerException is System.Data.SqlClient.SqlException))
    {
        var updateException = (System.Data.Entity.Core.UpdateException)exception.InnerException;

        var sqlException = (System.Data.SqlClient.SqlException)exception.InnerException.InnerException;
        var result = new List<ValidationResult>();

        for (int i = 0; i < sqlException.Errors.Count; i++)
        {
            builder.AppendLine(String.Format("Error code: {0} ", sqlException.Errors[i].Number));
            builder.AppendLine(String.Format("Source: {0} ", sqlException.Errors[i].Source));
            builder.AppendLine(String.Format("Message: {0} ", sqlException.Errors[i].Message));
            builder.AppendLine(String.Format("State: {0} ", sqlException.Errors[i].State));
            builder.AppendLine(String.Format("Procedure: {0} ", sqlException.Errors[i].Procedure));
        } 
    }
}

完成错误:

  

字符串或二进制数据将被截断。该语句已终止。

     

错误:输入tree_1ECACDBB4458C7A9DEC7CD183FD8B8C3473502FEFFACF160E17AD47718DCE5EA
  错误代码:8152
  来源:.Net SqlClient数据提供者
  消息:字符串或二进制数据将被截断   州:14
  步骤:
  错误代码:3621
  来源:.Net SqlClient数据提供者
  消息:该声明已被终止   州:0
  过程:

4 个答案:

答案 0 :(得分:5)

一个“丑陋”的解决方案(但功能齐全且仅使用C#代码)来确切地找到哪个属性会给您带来错误:

如果您正在进行更新,请执行以下操作:

 var myDBObj = db.Mytables.Where(x=>x.Id == myId).FirstOrDefaul();
 if(myDBObj == null) return false; // or something else with the error msg

 myDBObj.Property1 = myObjToSave.Property1;
 db.SaveChanges();

 myDBObj.Property2 = myObjToSave.Property2;
 db.SaveChanges();

 myDBObj.Property3 = myObjToSave.Property3;
 db.SaveChanges();
 .... // EACH PROPERTY....
 myDBObj.PropertyX = myObjToSave.PropertyX;
 db.SaveChanges();

现在,有一个制动点或增量变量来跟踪“位置”等......你会确切地知道在这种特殊情况下你有例外......

注意:这是一个丑陋的解决方案,只是为了追踪它在哪里令人心烦......永远不要在生产中使用它...当然IMO还有其他更友好的东西,比如拥有一个sql分析器并查看生成的SQL,然后尝试在sql管理工作室上运行它,然后在那里看到错误......

更新#1

这样的事情(注意:我没有编译它):P

Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties();  
string lastPropertyWithError = ""; // You can replace this with a list or so  
foreach (PropertyInfo property in properties)
{
   try{
    property.SetValue(myDBObj, property.GetValue(myObj, null));
    db.SaveChanges();
   }catch()
   {
     lastPropertyWithError  = property.Name;
   }
}

答案 1 :(得分:1)

使用Entity框架分析器从实体框架中捕获sql查询,找到更新查询并直接对数据库运行它,您很有可能找到该字段。

答案 2 :(得分:0)

ProspectName是可以截断的字段。不过,我不知道它是如何映射到您的数据库的。您可以在FluentApi或DataAnnotation中查找,具体取决于您的设置方式。

您需要查看为此字段设置的MaxLength,并确保它与您的数据库最大长度匹配。如果是,那么你需要确保你没有在这个字段上传递太长的字符串。也可能是实体和数据库之间的数据类型不匹配,因此也要检查。

目前,我没有太多其他信息可以帮助您。

答案 3 :(得分:0)

来自@Shaik:

public MyDbContext(string connectionString, ILogger<PeopleHrDbContext> logger)
    : base(connectionString)
{
    _logger = logger;
    Database.Log = logger.Debug;
}

我正在使用NLog和Ioc,因此您可以将记录器传递到您的ef上下文,并在您配置的日志输出中,您可以看到生成的查询的外观。对我来说这是调试输出窗口。我已经粘贴在我的NLog设置下面以支持此功能。

  <targets>
    <target xsi:type="Debugger" name="d" 
            layout="${longdate} ${logger} ${uppercase:${level}} ${message}" />
  </targets>

  <rules>
    <logger name="*" minlevel="Trace" writeTo="d" />
  </rules>