Estoy tratando de agregar un registro en una tabla, pero no está funcionando. El mensaje de error me dice que no puedo insertar un valor explícito en la columna de identidad para ProductCategories
, pero no sé si lo estoy haciendo. Tal vez hay algo que no entiendo sobre la navegación de la entidad, ¿o mis modelos no están correctamente vinculados?
SqlException: no se puede insertar un valor explícito para la columna de identidad en la tabla 'Categorías de productos' cuando IDENTITY_INSERT está desactivado. No se puede insertar un valor explícito para la columna de identidad en la tabla 'Productos' cuando IDENTITY_INSERT está desactivado. System.Data.SqlClient.SqlCommand + <> c.b__108_0 (Resultado de la tarea)
DbUpdateException: se produjo un error al actualizar las entradas. Vea la excepción interna para más detalles. Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch + d__32.MoveNext ()
Este es el código que falla (a la 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 });
}
Estos son los modelos de entidades involucradas:
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; }
}
La inspección de depuración del objeto fpp
muestra que los valores para ProductCategoryId
y ProductId
son correctos:
¿Dónde está / son mi error / s?
EDITAR Agregué la sugerencia [Key]
y [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
a todos los modelos, pero sigo recibiendo el mismo error.
Creo que el campo Id
siempre está configurado como clave principal como predeterminado en EF de todos modos.
EDITAR 2 Intenté agregar [FromBody]
en mi método de controlador, pero eso solo resultó en una pantalla en blanco, no [FromBody]
ningún mensaje de error ni se realizan cambios en la base de datos.
EDITAR 3 [ForeignKey("ProductId")]
y [ForeignKey("ProductCategoryId")]
al modelo de FrontPageProduct
, pero aún así obtengo la misma SqlException.
EDITAR 4 Estas son las claves foráneas de mis cuatro tablas:
FrontPageProducts
:
FK_FrontPageProducts_ProductCategories_ProductCategoryId
FK_FrontPageProducts_Products_ProductId
ProductCategories
:
FK_ProductCategories_ProductCategories_ParentId
Products
:
ninguna
ProductsInCategories
:
FK_ProductsInCategories_FrontPageProducts_FrontPageProductId
FK_ProductsInCategories_ProductCategories_ProductCategoryId
FK_ProductsInCategories_Products_ProductId
Parece que no es necesario establecer el atributo DatabaseGenerated para los campos "int Id", es una convención y se supone que es la columna de identidad. Por cierto, ¿estás seguro de que está recibiendo el mismo error? El enlace imgur no funciona para mí. ¿Realmente necesita Product y ProductCategory en su clase de FrontPage? Si puede comentarlos y probarlos fácilmente, hágalo. Si no, puede intentar establecer los valores para ellos como se muestra a continuación.
[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 });
}
Aplique los atributos Key y DatabaseGenerated a cada columna de Id en sus modelos, por lo que EF sabe que es una columna de identidad y necesita recuperar el valor de id generado.
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; }
}
Edición: debe agregar propiedades de navegación, tal como lo agregué anteriormente. Hacerlos virtuales también ayuda con la carga perezosa.
El campo Id debe ser la clave principal en la base de datos para que pueda especificar eso en los modelos de entidad. - Añadir la [clave]
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; }
}