【问题标题】:EF Core SqlException: Cannot insert explicit value for identity column in table 'MenuCategories' when IDENTITY_INSERT is set to OFFEF Core SqlException:当 IDENTITY_INSERT 设置为 OFF 时,无法在表“MenuCategories”中插入标识列的显式值
【发布时间】:2020-03-09 13:11:30
【问题描述】:

我正在尝试将一些数据保存到我的 MenuItems 表中,但我被错误阻止了

SqlException:当 IDENTITY_INSERT 设置为 OFF 时,无法在表“MenuCategories”中插入标识列的显式值

我只是尝试使用我拥有的类别 ID 设置外键,我不太清楚为什么会出现上述错误。

这是我的MenuItem 模型:

public class MenuItemViewModel
{
    [Key]
    [Column("MenuItem_Id")]
    public int MenuItemId { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public string Description { get; set; }

    [Required]
    public decimal Price { get; set; }

    [Required]
    [Column("MenuCategory_Id")]
    public MenuCategoryViewModel MenuCategory { get; set; }
}

这是我的MenuCategory 模型:

public class MenuCategoryViewModel
{
    [Key]
    [Column("MenuCategory_Id")]
    public int MenuCategoryId { get; set; }

    [Required]
    public string Name { get; set; }
}

我正在尝试为其分配现有类别的 id,我不希望它创建新类别。

【问题讨论】:

  • 提示:上面的错误表明您要插入的 Id 是 identity 列,这意味着您必须让数据库服务器控制它如何填充 @987654325 @ 除非您将 Identity_Insert 设置为关闭。我不是 Entity Framework Core 方面的专家,但您是否尝试在未填充 MenuItemId 的情况下传递对象?为什么你需要自己填写MenuItemId
  • @KristianneNerona 我正在尝试自己填充它,因为我想使用现有类别我不希望它创建一个新类别。
  • 能否确认MenuCategoryId是否定义为数据库中的IDENTITY列?

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


【解决方案1】:

我不得不假设你的DbContext 类是这样的:

public class Context: DbContext
{
    public Context(DbContextOptions<MenuContext> options)
        : base(options)
    { }

    public DbSet<MenuCategory> MenuCategories{ get; set; }
    public DbSet<MenuItem> MenuItems { get; set; }
}

所以你的控制器可以这样编码:

public async Task<IActionResult> Create(MenuItemViewModel model)
{
    if (ModelState.IsValid)
    {
        var menuItem = new MenuItem 
        {
            Name = model.Name,
            ...
        };

        var menuCategory = _Context.MenuCategories.Find(model.MenuCategory.MenuCategoryId);
        menuItem.MenuCategory = menuCategory;
        _Context.MenuItems.Add(menuItem);
        await _Context.SaveChangesAsync();
        return RedirectToAction(nameof(Index), new { id = menuItem.MenuCategory.MenuCategoryId });
    }
    return View(menuItem);
}

据我所知,您假设如果您告诉您的视图您的MenuCategory 具有选定的 id,您的视图将填充 MenuCategory。它不是那样工作的。该视图无法知道您的MenuCategory 是什么。您需要使用您的DbContext 填充这些值,这发生在您的控制器中。

此外,最好将 entitiesview models 分开。如果您的类有自己的简单职责,那就容易多了:您的实体将代表数据库中的逻辑记录,而您的视图模型将代表来自和去往您的控制器的数据。

【讨论】:

    【解决方案2】:

    基于您希望使用现有 ID 不添加新类别的 cmets,那么您为保存所做的操作有点错误 _Context.Add(menuItem); 将导致数据库 INSERT 触发 - 这是因为.Add() 将所有实体标记为要保存到上下文中的新实体,但您不希望这样 - 您应该做的是类似于添加 menuItem - 查询数据库以获取 MenuCategory你想附加到它 - 然后在menuItem上设置它,然后保存。

    【讨论】:

    • 哦,好吧,这解决了我的问题。所以每当我需要为我的外键使用现有的 id 时,我必须首先从数据库中获取它的对象,然后分配它然后保存它?
    • 一般情况下是的,这是因为您希望生成的 SQL 语句是通过现有实体的“更改跟踪”触发的更新
    【解决方案3】:

    如果您“隐式”将实体添加到数据库、保存它然后尝试手动添加,也会出现此错误。

    很明显,下面是可怕的代码,编写它没有任何意义。但是,在更复杂的情况下可能会意外地做到这一点。

    var category = new MenuCategoryViewModel() { ... };
    
    // assign category to menu item    
    var model = new MenuItemViewModel() 
                {
                    MenuCategory = category 
                };  
    
    db.Add(model);
    db.SaveChanges();
    
    // 'category' object has an ID because we saved it
    // even though it was never explicitly added to the context
    
    // add the category to the context 
    db.Add(category);
    db.SaveChanges();  // fails with IDENTITY error
    

    如果您在添加实体时未明确将其添加到上下文中,则您不得在已为其分配键后稍后再添加它。

    【讨论】:

      【解决方案4】:

      在我的情况下,抛出此异常是因为软件有一个具有自动生成 ID 的实体,并且我尝试在数据库中插入一条新记录,其 ID 由我的代码生成。解决方案很简单:删除我代码中设置的 ID。

      【讨论】:

        猜你喜欢
        • 2018-06-29
        • 2018-12-30
        • 2019-11-11
        • 2021-07-02
        • 1970-01-01
        • 2012-11-10
        • 1970-01-01
        • 2016-01-20
        • 1970-01-01
        相关资源
        最近更新 更多