【问题标题】:ASP.NET Core MVC models - SqlException cannot insert explicit value for identity columnASP.NET Core MVC 模型 - SqlException 无法为标识列插入显式值
【发布时间】:2020-01-28 05:04:55
【问题描述】:

我有一个与InventoryItem 类有关系的Stick 类。我有一个有一堆棍子的代码。我循环遍历这些棒以创建每个单独的 Stick 并将 InventoryItem 分配给该棒。

但是,当我尝试保存 DbContext 时,我收到一个错误

表 InventoryItems 的标识列出现 SqlException。

我不明白为什么,因为InventoryItem 在这之前就已经创建好了。我所做的只是在视图模型和视图之间来回传递InventoryItem

请看下图。如果我删除突出显示的代码行,那么DbContext 将能够保存并且我的InventoryItem 将是空的。

请在下面查看更多代码参考并提出建议。如果您需要更多信息,请告诉我。谢谢。

Error Image

棒类:

public class Stick
{
    public int Id { get; set; }
    public InventoryItem InventoryItem { get; set; }
}

InventoryItem 类:

public class InventoryItem
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string PartNumber { get; set; }
    public double Length { get; set; }
    public double GetLengthInInches => Math.Round(Length / 25.4, 0);
}

视图模型

public class OptimizationViewModel
{
    public InventoryItem InventoryItem { get; set; }
    public IList<Cut> TempInstanceCuts { get; set; }
    public IList<Stick> TempInstanceSticks { get; set; }
    public double[] Percents { get; set; }
    public int CutQuantity { get; set; }
    public double CutLength { get; set; }
    public int stickCount { get; set; }

    public OptimizationViewModel()
    {
        TempInstanceCuts = new List<Cut>();
        TempInstanceSticks = new List<Stick>();
    }
}

【问题讨论】:

  • 请包括任何相关的OnModelCreating 和更新代码。 EF 很可能认为您的 Id 密钥不是由数据库生成的。
  • @JeremyLakeman 我的代码没有 OnModelCreating。我会阅读它,看看它是否可以帮助我解决这个问题。将报告我的发现。谢谢。

标签: c# sql-server asp.net-mvc entity-framework asp.net-core


【解决方案1】:

您似乎为InventoryItem 实体手动设置了Id 值。您不应该这样做,因为它是自动生成的。创建此实体时忽略它。

【讨论】:

  • 嗨,我本来打算这样。我想先创建 InventoryItem,将其传递给 View,然后将其传递回 StickController,然后创建一堆单独的棒,然后映射到它们的父级 InventoryItem。
【解决方案2】:

这是一个简单的省略:如果表中有INT IDENTITY 列,则需要在模型类的键列上添加[DatabaseGenerated(DatabaseGeneratedOption.Identity)] 注释:

public class InventoryItem
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }
    public string PartNumber { get; set; }
    public double Length { get; set; }
    public double GetLengthInInches => Math.Round(Length / 25.4, 0);
}

如果StickId 也是一个标识列,那么在您的模型类中也对该列执行相同的操作。

该注释只是告诉 EF 该列是由 SQL Server 处理的标识列,并且 EF 应忽略您可能分配给它的任何值,并且不将该列包含到 INSERT 语句中。

更新 #2: 似乎 EF Core 有一个新的默认行为,可以自动假定数据库将任何非复合主键作为“生成的属性”处理”。感谢@LazZiya 的指点:Generated value on Add

【讨论】:

  • 我认为 KeyAttribute 类实现了相同的功能,同时还为 Code First 设置了 PRIMARY KEY 标志,假设它是一个整数列。
  • 如果列名是Id,则不需要使用[Key][DataBaseGenerated...]配置为主键。如docs 中所述:“按照约定,名为Id&lt;type name&gt; Id 的属性将被配置为实体的主键。
  • @marc_s,一个名为Id的属性将默认配置为主键。并且将具有value generated on add "按照惯例,如果应用程序未提供值,则将设置为 short、int、long 或 Guid 类型的非复合主键为插入的实体生成值。 "
  • @LazZiya:有趣 - 谢谢你的链接 - 这是 EF Core 中的新功能(在 .NET 4.x 中的“经典”EF 中绝对不是这种情况)
  • @marc_s 不客气 :) 顺便说一句,这是Code First Conventions 的另一个有用资源
【解决方案3】:

如果要手动设置InventoryItem模型的主键值,需要使用[DatabaseGenerated(DatabaseGeneratedOption.None)]属性。

public class InventoryItem
{
   [DatabaseGenerated(DatabaseGeneratedOption.None)] 
   public int Id { get; set; }   
   //other properties 
}

参考https://docs.microsoft.com/en-us/ef/core/modeling/generated-properties?tabs=data-annotations#no-value-generation-1

【讨论】:

    【解决方案4】:

    所以我花时间阅读了其中的一些内容并决定重写我的课程。我发现真正有用的是我需要添加一个额外的属性,比如 ForeignKeyID 确实可以帮助我处理相关数据。如:

    public class Stick
    {
       public int Id { get; set; }
       public InventoryItem InventoryItem { get; set; }
       public int ForeignKeyInventoryItemID { get; set; }
    }
    

    感谢您的文档。

    【讨论】:

      猜你喜欢
      • 2019-05-28
      • 2017-12-31
      • 2015-10-27
      • 1970-01-01
      • 2021-11-26
      • 2020-03-09
      • 2018-06-29
      • 2016-04-13
      相关资源
      最近更新 更多