Getting DbUpdateException when adding a row - c#

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:
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

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.

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

How to Add related entites to database using EntityFramework

I am trying add the cart to database but don't know how to add related Entities
My related tables are ( carts , products , productoptions , options)
How Can I add or Update those tables at the same time? And how can I set Foreign keys to related Tables
thanks...
You will create models for each of your tables (see below)
Then if you add just a child you will have to add it with the foreig nkey property populated
var test = childObj { parentPropertyId = parentPropertyIdValue}
If you add parent and child together you can just add and entity mework will take care of that. For example:
var test = new parentObj {
someProperty = someValue,
childProperty = new childObj{
//here will not have to populate the parentPropertyId
}
}
See sample models for your above tables
Use the [Key] attribute to specify your primary key
Use the [ForeignKey] attribute above your related entity property to specify which property to use as foreign key
Use an ICollection to access the children of an object
public class Carts
{
[Key]
public int Id { get; set; }
public int Userid { get; set; }
public DateTime CreatedDate { get; set; }
public ICollection<Products> Products { get; set; }
}
public class Products
{
[Key]
public int Id { get; set; }
public string SerialNumber { get; set; }
public string StockCode { get; set; }
public int CartId { get; set; }
public int Quantity { get; set; }
[ForeignKey(nameof(CartId))]
public Carts Cart { get; set; }
}
public class ProductOptions
{
[Key]
public int Id { get; set; }
public int ProductId { get; set; }
public int OptionId { get; set; }
[ForeignKey(nameof(ProductId))]
public Products Products { get; set; }
[ForeignKey(nameof(OptionId))]
public Options Options { get; set; }
}
public class Options
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
public int ParentId { get; set; }
public int GrandParentId { get; set; }
}

how to update the model class recipe?

I have two model classes Category and Recipe and their relationship in one to many. I want to Edit the Recipe and also change the category that the recipe belongs to.Thanks in advance.
public class CookContext : DbContext
{
public CookContext(): base("cookContext")
{
}
public DbSet<Recipe> Recipes { get; set; }
public DbSet<Category> Categories { get; set; }
}
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Recipe> Recipes { get; set; }
}
public class Recipe
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string Ingridients { get; set; }
public string Image { get; set; }
public Category category { get; set; }
}
[HttpPost]
[ValidateInput(false)]
public ActionResult EditRecipe(Recipe recipe, int? categoryName)
{
var category = context.Categories.Where(c => c.Id ==
(int)categoryName).FirstOrDefault();
context.Entry(recipe).State = EntityState.Modified;
recipe.category = category;
context.SaveChanges();
}
The error messages i get are:
1.
[DbUpdateException: An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types.
2.
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.
Try by adding the field CategoryId to your Recipe class, also, the category property should begin with a capital "C".
The collection property should be marked virtual if you want the data to be lazy loaded (only loaded when needed) otherwise, you may load all recipes for a given category every time you make a query:
public class Recipe
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string Ingridients { get; set; }
public string Image { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Recipe> Recipes { get; set; }
}
If it doesn't work try by setting up the ForeignKey attribute:
public class Recipe
{
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
[Required]
public string Ingredients { get; set; }
public string Image { get; set; }
[ForeignKey("Category")]
public int CategoryId { get; set; }
public Category Category { get; set; }
}
public class Category
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Recipe> Recipes { get; set; }
}

How to create a foreign relation to one Model from multiple other models using Entity framework?

I am trying to create my first app using ASP.NET MVC framework and Entity Framework 6.
I chose to use code first approach and I started by defining my Models.
I have a model called Client with an identity attribute called Id. I have multiple Models that has an attribute called ClientId. The ClientId attribute should have virtual link to the Clients Model.
Here is how my Client model looks like
[Table("clients")]
public class Client
{
[Key]
public int id { get; set; }
public string name { get; set; }
public string status { get; set; }
public DateTime created_at { get; set; }
public DateTime? modified_at { get; set; }
public Client()
{
status = "Active";
created_at = DateTime.UtcNow;
}
}
Then here is how I am creating a belong to relation using other models.
[Table("BaseClientsToUsers")]
public class ClientToUser : ModelDefault
{
[ForeignKey("User")]
public int UserID { get; set; }
[ForeignKey("Client")]
public int ClientId { get; set; }
[ForeignKey("Team")]
public int DefaultTeamId { get; set; }
public DateTime? JoinedAt { get; set; }
public bool IsActive { get; set; }
public virtual User User { get; set; }
public virtual Client Client { get; set; }
public virtual Team Team { get; set; }
public ClientToUser()
{
DateTime UtcNow = DateTime.UtcNow;
IsActive = true;
CreatedAt = UtcNow;
LastUpdatedAt = UtcNow;
}
[Table("BaseTeams")]
public class Team : ModelDefault
{
[MaxLength(250)]
public string Name { get; set; }
[ForeignKey("Client")]
public int ClientId { get; set; }
public bool IsActive { get; set; }
public virtual Client Client { get; set; }
public Team()
{
DateTime UtcNow = DateTime.UtcNow;
IsActive = true;
CreatedAt = UtcNow;
LastUpdatedAt = UtcNow;
}
}
But, when I try to update my databases I get the following error
Introducing FOREIGN KEY constraint
'FK_dbo.BaseTeams_dbo.BaseClients_ClientId' on table 'BaseTeams' may
cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or
ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could
not create constraint or index. See previous errors.
I am not really sure what could be causing the error but it seems it is because I am creating multiple Foreign keys to the same `Clients model.
How can I fix this error?
Hello #Mike A When I started MVC I got this error too, so you need aditional tables that connects your DB items.
So try connect your database items with tables like that:
Here is my working example:
[Table("Products")]
public class Product
{
[Key]
public string Id { get; set; }
[Required]
public string Name { get; set; }
public string Description { get; set; }
public int Quantity { get; set; }
public decimal Price { get; set; }
public decimal InternalPrice { get; set; }
public string Url { get; set; }
}
[Table("Categories")]
public class Category
{
[Key]
public string Id { get; set; }
[Required]
public string Name { get; set; }
public string Url { get; set; }
}
[Table("ProductCategories")]
public class ProductCategory
{
[Key]
[Column(Order = 0)]
public string ProductId { get; set; }
[Key]
[Column(Order = 1)]
public string CategoryId { get; set; }
public virtual Category Category { get; set; }
}
So you can connect your items without problems hope this will help you.

Ambiguous match found exception in BindingListView

I keep getting this exception while using Andrew Davey's BindingListView (http://blw.sourceforge.net/). I am using ServiceStack OrmLite . My objects looks like this:
public class Category
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[StringLength(50)]
public string Name { get; set; }
}
and
public class Product
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[References(typeof(Category))]
public int CategoryId { get; set; }
public int ProductTypeId { get; set; }
[StringLength(50)]
public string Name { get; set; }
[Reference]
public Category Category { get; set; }
}
I have no idea how to pass this exception.
Edit
The exception occurs on the first line of the following code:
var products = dbConn.Select<Product>().OrderBy(p => p.Name).ToList();
var productsView = new BindingListView<Product>(products);
dgProducts.DataSource = productsView;
you have
product.Name
product.Category.Name
product.Id
product.Category.Id
when that lib does reflection to get Property, it gets 2 "Name".
code doesnt know, Which one do you want. Product.Name from or Product.Category.Name.
tldr: easy fix is to change one of properties names
public class Category
{
public int cId { get; set; }
public string cName { get; set; }
}
public class Product
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[References(typeof(Category))]
public int CategoryId { get; set; }
public int ProductTypeId { get; set; }
[StringLength(50)]
public string Name { get; set; }
[Reference]
public Category Category { get; set; }
}

Last inserted id with EF 4.1 , MVC 3

I'm using asp.net mvc 3 and EF 4.1 with visual studio 2010 and im new to it.
i have a problem about last inserted id. i have two table in my db "points_Order" and "points_OrderDetails".
db.Order.Add(po);
db.SaveChanges();
//second thing i have tried
var orderID = (from oi in db.Order
select oi.ID)
.Max(i => i);
// and this first thing
pod.OrderID = po.ID;
pod.OrderID = orderID;
db.OrderDetails.Add(pod);
db.SaveChanges();
context class:
public class points_Order {
[Key]
public int ID { get; set; }
public string Owner { get; set; }
public DateTime Date { get; set; }
public byte Status { get; set; }
public int Total { get; set; }
//public virtual points_OrderDetails OrderDetail { get; set; }
}
public class points_OrderDetails {
[Key]
public int OrderID { get; set; }
public string OrderType { get; set; }
public int Amount { get; set; }
public int ItemID { get; set; }
public int ItemRecord { get; set; }
public string ItemCode { get; set; }
public byte Plus { get; set; }
public byte Degree { get; set; }
public string Kind { get; set; }
public string Sex { get; set; }
public string Race { get; set; }
public string Tier { get; set; }
public string SetItem { get; set; }
public string SOX { get; set; }
//public Blues Blue { get; set; }
}
public DbSet<points_Order> Order { get; set; }
public DbSet<points_OrderDetails> OrderDetails { get; set; }
im getting the error "{"Cannot insert the value NULL into column 'OrderID', table 'db.dbo.points_OrderDetails'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."}"
what can i do? am i doing something wrong?
If you define a relationship from order -> order details in your model, it should work like this:
po.Details.Add(pod); // or pod.Order = po;
db.Order.Add(po);
db.SaveChanges();
EF should figure out the relations for you, no need to set ID's manually.
UPDATE: you're trying to do something that is not supported. You have a one-to-one mapping; EF does not support it the way you intend to (shared primary key). See http://weblogs.asp.net/manavi/archive/2011/05/01/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations.aspx for an explanation on how to model one-to-one in EF.

Categories

Resources