更新SQL Server表时在DbUpdateException中获取InvalidCastException

时间:2019-02-06 22:43:11

标签: c# asp.net-mvc entity-framework exception

我们有一个数据库管理Web应用程序,该应用程序可以创建,更新和删除SQL Server数据库中的条目。使用ASP.NET MVC构建并使用Entity Framework 2.2,该应用程序在创建和更新数据库中的几乎所有表时都能成功运行。但是,我在更新特定表时遇到Db更新异常。内部的例外是

  

无效的强制转换异常:“无法将类型为'System.String'的对象强制转换为类型为'System.Int32'

使用EF Core Power Tools创建了该表的模型,以包括该表中的所有列。我可以在表中创建新条目而不会出现问题,但是当我使用应用程序更新ANY值时,我得到了异常。有一个用于创建的视图和一个用于编辑的视图。此问题表大约有50列,其中包含2列和1个不可为空的列的串联主数据库。所有其他列均允许NULLS。

我可以创建一条记录,其中填充的值很少或全部没有问题。我可以编辑条目而无需进行更改。但是,只要我对任何字段进行更改,都会收到错误消息。

我尝试消除某些字段以缩小字段的范围,但这是徒劳的。我已对模型类中属性的数据类型与表的数据类型对齐进行了三重检查。一切都是正确的……此外,如果不是这样,那么在创建时会出现相同的错误。

这是我的截断模型类:

public partial class SC_CUSTOM_STYLE_SPEC
{
    [DataTablesAttributeRowId]
    public string RowId { get { return String.Format("{0}_{1}", SELLING_STYLE_NBR, CUST_REFERENCE_NBR); } }
    [Required]
    [StringLength(5)]
    public string SELLING_STYLE_NBR { get; set; }
    [StringLength(2)]
    public string selling_company { get; set; }
    public string density { get; set; }
    [StringLength(100)]
    public string construction_type { get; set; }
    [StringLength(50)]
    public string electrstatic_propensity { get; set; }
    [StringLength(100)]
    public string protective_treatments { get; set; }
    [StringLength(50)]
    public string smoke_density { get; set; }
    [StringLength(50)]
    public string long_name { get; set; }
    public int? introduction_date { get; set; }
    public string stitches_per_inch { get; set; }
    [Required]
    [StringLength(3)]
    public string CUST_REFERENCE_NBR { get; set; }
    [StringLength(50)]
    public string greige_good_nbr { get; set; }
    [StringLength(50)]
    public string inventory_style_nbr { get; set; }
    public bool? is18x36 { get; set; }
    public bool? isHex { get; set; }
    public bool? enableViz { get; set; }
    public bool? enableCustomViz { get; set; }
    public bool? enableGenericViz { get; set; }
    public bool? is9x36Tile { get; set; }
    public bool? isFacetTile { get; set; }
    public int? product_subtype_id { get; set; }
    ...

这是我的控制器中的Create方法:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("SELLING_STYLE_NBR,selling_company,...")] SC_CUSTOM_STYLE_SPEC sC_CUSTOM_STYLE_SPEC)
{
   if (ModelState.IsValid)
   {
        _context.Add(sC_CUSTOM_STYLE_SPEC);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(sC_CUSTOM_STYLE_SPEC);
}

这是我的Edit方法:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(string id, [Bind("SELLING_STYLE_NBR,selling_company,...")] SC_CUSTOM_STYLE_SPEC sC_CUSTOM_STYLE_SPEC)
{
    if (ModelState.IsValid)
    {
        try
        {
            _context.Update(sC_CUSTOM_STYLE_SPEC);
            await _context.SaveChangesAsync();
        }
        catch (DbUpdateConcurrencyException ex)
        {
            if (!SC_CUSTOM_STYLE_SPECExists(sC_CUSTOM_STYLE_SPEC.SELLING_STYLE_NBR))
            {
                return NotFound();
            }
            else
            {
                throw;
            }
        }
        catch (DbUpdateException ex)
        {
            var exception = HandleDbException(ex);
            return View("Error", new System.Web.Mvc.HandleErrorInfo(exception,"SC_CUSTOM_STYLE_SPEC","Edit"));
        }

        // redirect back to List page if referrer is available (only for models with FK)
        var referrer = Request.Form["Referrer"];

        if (String.IsNullOrEmpty(referrer))
            return RedirectToAction(nameof(Index));
        else
            return Redirect(referrer);
    }

    return View(sC_CUSTOM_STYLE_SPEC);
}

这是堆栈:

  

Microsoft.EntityFrameworkCore.DbUpdateException:发生错误   在更新条目时。有关详细信息,请参见内部异常。 ->   System.InvalidCastException:无法转换类型的对象   “ System.String”键入“ System.Int32”。

     

在System.Data.SqlClient.SqlBuffer.get_Int32()

     

在System.Data.SqlClient.SqlDataReader.GetInt32(Int32 i)

     在

  Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeResultSetWithoutPropagationAsync(Int32   commandIndex,RelationalDataReader阅读器,CancellationToken   cancelToken)

     在

  Microsoft.EntityFrameworkCore.Update.AffectedCountModificationCommandBatch.ConsumeAsync(RelationalDataReader   读取器,CancellationToken CancellationToken)

     

---内部异常堆栈跟踪的结尾---

     在

  CPSDataAdmin.Controllers.SC_CUSTOM_STYLE_SPECController.Edit(字符串   id,SC_CUSTOM_STYLE_SPEC sC_CUSTOM_STYLE_SPEC)   C:\ Projects \ cps-data-admin \ CPSDataAdmin \ Controllers \ SC_CUSTOM_STYLE_SPECController.cs:line 379

     在

  Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper   映射器,ObjectMethodExecutor执行器,对象控制器,Object []   参数)

     

在System.Threading.Tasks.ValueTask`1.get_Result()

     在

  Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()

     在

  Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()

     在

  Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext   上下文)

     在

  Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State&   接下来,范围和范围,对象和状态,布尔值和isCompleted)

     在

  Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()

     在

  Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()

     在

  Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext   上下文)

     Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State&   接下来,范围和范围,对象和状态,布尔值和isCompleted)

     在

  Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()

     

在Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()

     在Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext   httpContext)

     在

  Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext   上下文)

     在

  Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext   上下文)

     在

  Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext   上下文)

     在

  Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext   httpContext)

     在

  Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext   httpContext)

     在

  Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext   上下文)

2 个答案:

答案 0 :(得分:0)

[DataTablesAttributeRowId]属性是什么?您的表中是否有一个名为“ RowId”的列?您提到了一个级联(复合?)键。通常,如果这是由2x列组成的PK,则应声明一个Key映射:

[Key, Column(Order = 0)]
[Required] 
[StringLength(5)]
public string SELLING_STYLE_NBR { get; set; }
// ...
[Key, Column(Order = 1)]
[Required]
[StringLength(3)]
public string CUST_REFERENCE_NBR { get; set; }

在数据库中,这两个都是Varchar / NVarchar列吗?在名称暗示它们是数字的系统中使用文本PK / FK似乎很不寻常。

实体声明应反映表架构和表之间的关系。为了帮助评估映射问题,请包括相关的表格结构。您的代码示例中有一些气味,包括该属性和不同的命名约定。

答案 1 :(得分:0)

检查桌上的触发器!我遇到同样的问题时发现了这个问题,而我的问题却是执行选择的触发器。

EF沿着以下内容运行语句

SET NOCOUNT ON;
UPDATE [ProblemTable] SET [IrrelevantColumn] = @p0
WHERE [id] = @p1;
SELECT @@ROWCOUNT;

,并且只希望返回@@ rowcount结果集。触发器正在从受影响的行中选择一个varchar列,这使EF试图从“ ABC1234DEF”解析行计数。我不知道为什么触发器要执行该选择,但是我认为它归结于我在生产中进行调试的前任之一。