Getting DbUpdateException when adding a row

asp.net-core c# code-first entity-framework-core linq

Question

I'm trying to add a record in a table, but it's not working. The error message tells me that I cannot insert an explicit value in identity column for ProductCategories, but I don't know that I'm doing that. Maybe there is something I'm not getting about entity navigation, or my models are somehow not correctly linked?

SqlException: Cannot insert explicit value for identity column in table 'ProductCategories' when IDENTITY_INSERT is set to OFF. Cannot insert explicit value for identity column in table 'Products' when IDENTITY_INSERT is set to OFF. System.Data.SqlClient.SqlCommand+<>c.b__108_0(Task result)

DbUpdateException: An error occurred while updating the entries. See the inner exception for details. Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch+d__32.MoveNext()

This is the code that fails (at await _context.SaveChangesAsync();):

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> FrontPageProduct(ViewModelFrontPageProduct frontPageProduct)
{
    var fpp = new FrontPageProduct()
    {
        ProductCategoryId = frontPageProduct.ProductCategoryId,
        ProductId = frontPageProduct.ProductId,
        SortOrder = 0
    };
    _context.Add(fpp);
    await _context.SaveChangesAsync();
    return View("Index", new { id = fpp.ProductCategoryId, tab = 2 });
}

These are the involved entity models:

public class Product
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Title { get; set; }
    public string Info { get; set; }
    public decimal Price { get; set; }
    public List<FrontPageProduct> InFrontPages { get; set; }
    public List<ProductInCategory> InCategories { get; set; }
}

public class ProductCategory
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public int SortOrder { get; set; }
    public string Title { get; set; }
    [ForeignKey(nameof(ParentCategory))]
    public int? ParentId { get; set; }
    public ProductCategory ParentCategory { get; set; }
    public ICollection<ProductCategory> Children { get; set; } = new List<ProductCategory>();
    public List<ProductInCategory> ProductInCategory { get; set; }
}

public class FrontPageProduct
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public int ProductCategoryId { get; set; }
    public int ProductId { get; set; }
    public int SortOrder { get; set; }
    [ForeignKey("ProductId")]
    public virtual Product Product { get; set; }
    [ForeignKey("ProductCategoryId")]
    public virtual ProductCategory ProductCategory { get; set; }
}

The debug inspection of the fpp-object shows that the values for ProductCategoryId and ProductId are correct:

Debug-info

Where is/are my mistake/s?

EDIT I added the suggested [Key] and [DatabaseGenerated(DatabaseGeneratedOption.Identity)] to all the models, but I still get the same error.

I think that the Id field is always set to be primary key as default in EF anyway.

EDIT 2 I tried adding [FromBody] in my controller method, but that only resulted in a blank screen, no error message, and no changes being made to the database.

EDIT 3 I added [ForeignKey("ProductId")] and [ForeignKey("ProductCategoryId")] to the FrontPageProduct model, but still get the same SqlException.

EDIT 4 These are the foreign keys of my four tables:

FrontPageProducts:

FK_FrontPageProducts_ProductCategories_ProductCategoryId

FK_FrontPageProducts_Products_ProductId

ProductCategories:

FK_ProductCategories_ProductCategories_ParentId

Products:

none

ProductsInCategories:

FK_ProductsInCategories_FrontPageProducts_FrontPageProductId

FK_ProductsInCategories_ProductCategories_ProductCategoryId

FK_ProductsInCategories_Products_ProductId

1
0
2/8/2018 10:31:38 AM

Accepted Answer

Looks like you don't need to set DatabaseGenerated attribute for "int Id" fields, it is a convention and assumed that it is Identity Column. Btw, are you sure you are getting the same error? The imgur link does not work for me. Do you really need Product and ProductCategory on your FrontPage class, if you can easily comment them out and test, please do so, if not you can try setting the values for them like below.

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> FrontPageProduct(ViewModelFrontPageProduct frontPageProduct)
{
    var fpp = new FrontPageProduct()
    {
        ProductCategoryId = frontPageProduct.ProductCategoryId,
        ProductId = frontPageProduct.ProductId,
Product = _context.Set<Product>().Find(frontPageProduct.ProductId),
ProductCategory = _context.Set<ProductCategory>().Find(frontPageProduct.ProductCategoryId),
        SortOrder = 0
    };
    _context.Add(fpp);
    await _context.SaveChangesAsync();
    return View("Index", new { id = fpp.ProductCategoryId, tab = 2 });
}

Apply Key and DatabaseGenerated attributes to every Id column on your models, so EF knows that it is an identity column and it needs to get back the generated id value.

    public class Product
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public string Title { get; set; }
        public string Info { get; set; }
        public decimal Price { get; set; }
[InverseProperty("Product")]
        public IEnumerable<FrontPageProduct> InFrontPages { get; set; }
        public List<ProductInCategory> InCategories { get; set; }
    }

    public class ProductCategory
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public int SortOrder { get; set; }
        public string Title { get; set; }
        [ForeignKey(nameof(ParentCategory))]
        public int? ParentId { get; set; }
        public ProductCategory ParentCategory { get; set; }
        public ICollection<ProductCategory> Children { get; set; } = new List<ProductCategory>();
        public List<ProductInCategory> ProductInCategory { get; set; }
    }

    public class FrontPageProduct
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        public int ProductCategoryId { get; set; }
        public int ProductId { get; set; }
        public int SortOrder { get; set; }
    [ForeignKey("ProductId")]
        public virtual Product Product { get; set; }
    [ForeignKey("ProductCategoryId ")]
        public virtual ProductCategory ProductCategory { get; set; }
    }

Edit: you should add navigation properties, just like I added above. Making them virtual also helps with lazy loading.

1
2/8/2018 10:38:51 AM

Popular Answer

The Id field should be the primary key in the database so you can specify that in the entity models. - Add the [Key]

public class Product
{
    [Key]
    public int Id { get; set; }
    public string Title { get; set; }
    public string Info { get; set; }
    public decimal Price { get; set; }
    public IEnumerable<FrontPageProduct> InFrontPages { get; set; }
    public List<ProductInCategory> InCategories { get; set; }
}


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow