I am developing my first MVC application that has a store full of items. Each item can have zero or many modifiers attached to it (Small, Medium, Large, etc...)
Everything is working, except when I try to edit the item, the modifier associations are not updating with the item. I have verified the data is being passed to my object, but when I call db.SaveChanges(), those associations are not changed (all other item
information is updated fine)
My StoreItem Model:
public class StoreItem
{
public int ID { get; set; }
...
public virtual ICollection<StoreItemModifier> StoreItemModifiers { get; set; }
}
My StoreItemModifier Model:
public class StoreItemModifier
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<StoreItem> StoreItems { get; set; }
}
And in my DbContext onModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Help define relationships between store items and modifiers
modelBuilder.Entity<StoreItem>()
.HasMany(s => s.MasterItemModifiers).WithMany(m => m.StoreItems)
.Map(t => t.MapLeftKey("StoreItemID")
.MapRightKey("StoreItemModifierID")
.ToTable("StoreItemModifierAssignments"));
}
And finally, here is the code from my controller, which is trying to update the model in the database:
[HttpPost]
public ActionResult Edit(int id, StoreItemViewModel viewModel, HttpPostedFileBase postedFile)
{
if (ModelState.IsValid)
{
var storeItem = new StoreItem
{
ID = viewModel.ID,
ConceptID = viewModel.ConceptID,
Name = viewModel.Name,
Description = viewModel.Description,
StoreSubCategoryID = viewModel.StoreSubCategoryID,
RestaurantGLAccount = viewModel.RestaurantGLAccount,
MarketingGLAccount = viewModel.MarketingGLAccount,
SupplierInstructions = viewModel.SupplierInstructions,
SupplierScheduleID = viewModel.SupplierScheduleID,
Price = viewModel.Price,
StoreItemModifiers = StoreItemModifier.getModifiers(db, viewModel.SelectedModifiers)
};
db.Entry(storeItem).State = System.Data.EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Items", "StoreSubCategory", new { id = viewModel.StoreSubCategoryID });
}
...
}
The following line takes an array of IDs from the viewModel and returns a list of StoreItemModifiers from the database. I have ensured this is working.
I haven't seen your chaning to the property of "StoreItemModifiers" for StoreItem, please make sure that you've assigned right correct value collection to this property.
OK... had some problems updating the image field as well so I did some more googling and figured out what I was doing wrong.
You have to attach an object to the DBContext before adding references to other entities. Here is my modified controller code:
var storeItem = new StoreItem
{
ID = viewModel.ID,
ConceptID = viewModel.ConceptID,
Name = viewModel.Name,
Description = viewModel.Description,
StoreSubCategoryID = viewModel.StoreSubCategoryID,
RestaurantGLAccount = viewModel.RestaurantGLAccount,
MarketingGLAccount = viewModel.MarketingGLAccount,
SupplierInstructions = viewModel.SupplierInstructions,
SupplierScheduleID = viewModel.SupplierScheduleID,
Price = viewModel.Price
};
//we need to attach the item to the context before assigning any entity references on the properties
db.StoreItems.Attach(storeItem);
storeItem.StoreItemModifiers = StoreItemModifier.getModifiers(db, viewModel.SelectedModifiers);
//if there was a file posted with the response, add it to the Item
if (postedFile != null)
{
var imageAsset = new Asset
{
Contents = new byte[postedFile.ContentLength],
Name = postedFile.FileName,
MimeType = postedFile.ContentType
};
//our Asset has been created, but the contents have not been filled yet
//read the data from the postedFile into the object's byte array
postedFile.InputStream.Read(imageAsset.Contents, 0, postedFile.ContentLength);
storeItem.Image = imageAsset;
}
db.SaveChanges();
I modified the code in the controller to the following:
var storeItem = db.StoreItems.Find(id);
storeItem.ConceptID = viewModel.ConceptID;
storeItem.Name = viewModel.Name;
storeItem.Description = viewModel.Description;
storeItem.StoreSubCategoryID = viewModel.StoreSubCategoryID;
storeItem.RestaurantGLAccount = viewModel.RestaurantGLAccount;
storeItem.MarketingGLAccount = viewModel.MarketingGLAccount;
storeItem.SupplierInstructions = viewModel.SupplierInstructions;
storeItem.SupplierScheduleID = viewModel.SupplierScheduleID;
storeItem.Price = viewModel.Price;
storeItem.StoreItemModifiers = StoreItemModifier.getModifiers(db, viewModel.SelectedModifiers);
//if there was a file posted with the response, add it to the Item
if (postedFile != null)
{
...
}
db.SaveChanges();
This code will add new modifiers to the item, but will not remove modifiers that are no longer selected, and will throw an exception if an existing modifier is left checked:
Violation of PRIMARY KEY constraint 'PK_dbo.StoreItemModifierAssignments'. Cannot insert duplicate key in object 'dbo.StoreItemModifierAssignments'.
IE:
create an item with modifiers Small and Medium
edit item and select an extra modifier 'Large'
'Small', 'Medium' and 'Large' are now selected
Submit the form
Receive exception, because it is trying to create NEW associations for Small and Medium
Yes, I understand. But what is happening is that instead of updating the existing records, EF is attempting to create NEW records (causing the PK violation)
I've tried several things, but can't seem to figure out how to get EF to handle updating the associations automatically.
mgasparel
Member
298 Points
65 Posts
Removing records from a one to zero or many relationship
Jan 20, 2013 12:25 PM|LINK
I am developing my first MVC application that has a store full of items. Each item can have zero or many modifiers attached to it (Small, Medium, Large, etc...)
Everything is working, except when I try to edit the item, the modifier associations are not updating with the item. I have verified the data is being passed to my object, but when I call db.SaveChanges(), those associations are not changed (all other item information is updated fine)
My StoreItem Model:
public class StoreItem { public int ID { get; set; } ... public virtual ICollection<StoreItemModifier> StoreItemModifiers { get; set; } }My StoreItemModifier Model:
public class StoreItemModifier { public int ID { get; set; } public string Name { get; set; } public virtual ICollection<StoreItem> StoreItems { get; set; } }And in my DbContext onModelCreating:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { //Help define relationships between store items and modifiers modelBuilder.Entity<StoreItem>() .HasMany(s => s.MasterItemModifiers).WithMany(m => m.StoreItems) .Map(t => t.MapLeftKey("StoreItemID") .MapRightKey("StoreItemModifierID") .ToTable("StoreItemModifierAssignments")); }And finally, here is the code from my controller, which is trying to update the model in the database:
[HttpPost] public ActionResult Edit(int id, StoreItemViewModel viewModel, HttpPostedFileBase postedFile) { if (ModelState.IsValid) { var storeItem = new StoreItem { ID = viewModel.ID, ConceptID = viewModel.ConceptID, Name = viewModel.Name, Description = viewModel.Description, StoreSubCategoryID = viewModel.StoreSubCategoryID, RestaurantGLAccount = viewModel.RestaurantGLAccount, MarketingGLAccount = viewModel.MarketingGLAccount, SupplierInstructions = viewModel.SupplierInstructions, SupplierScheduleID = viewModel.SupplierScheduleID, Price = viewModel.Price, StoreItemModifiers = StoreItemModifier.getModifiers(db, viewModel.SelectedModifiers) }; db.Entry(storeItem).State = System.Data.EntityState.Modified; db.SaveChanges(); return RedirectToAction("Items", "StoreSubCategory", new { id = viewModel.StoreSubCategoryID }); } ... }The following line takes an array of IDs from the viewModel and returns a list of StoreItemModifiers from the database. I have ensured this is working.
Decker Dong ...
All-Star
118619 Points
18779 Posts
Re: Removing records from a one to zero or many relationship
Jan 22, 2013 01:29 AM|LINK
Hi,
I haven't seen your chaning to the property of "StoreItemModifiers" for StoreItem, please make sure that you've assigned right correct value collection to this property.
Reguards!
mgasparel
Member
298 Points
65 Posts
Re: Removing records from a one to zero or many relationship
Jan 22, 2013 02:19 AM|LINK
OK... had some problems updating the image field as well so I did some more googling and figured out what I was doing wrong.
You have to attach an object to the DBContext before adding references to other entities. Here is my modified controller code:
var storeItem = new StoreItem { ID = viewModel.ID, ConceptID = viewModel.ConceptID, Name = viewModel.Name, Description = viewModel.Description, StoreSubCategoryID = viewModel.StoreSubCategoryID, RestaurantGLAccount = viewModel.RestaurantGLAccount, MarketingGLAccount = viewModel.MarketingGLAccount, SupplierInstructions = viewModel.SupplierInstructions, SupplierScheduleID = viewModel.SupplierScheduleID, Price = viewModel.Price }; //we need to attach the item to the context before assigning any entity references on the properties db.StoreItems.Attach(storeItem); storeItem.StoreItemModifiers = StoreItemModifier.getModifiers(db, viewModel.SelectedModifiers); //if there was a file posted with the response, add it to the Item if (postedFile != null) { var imageAsset = new Asset { Contents = new byte[postedFile.ContentLength], Name = postedFile.FileName, MimeType = postedFile.ContentType }; //our Asset has been created, but the contents have not been filled yet //read the data from the postedFile into the object's byte array postedFile.InputStream.Read(imageAsset.Contents, 0, postedFile.ContentLength); storeItem.Image = imageAsset; } db.SaveChanges();Decker Dong ...
All-Star
118619 Points
18779 Posts
Re: Removing records from a one to zero or many relationship
Jan 22, 2013 03:19 AM|LINK
Hi,
Please upsite-down the two statements and have a try.
mgasparel
Member
298 Points
65 Posts
Re: Removing records from a one to zero or many relationship
Jan 24, 2013 02:26 PM|LINK
I modified the code in the controller to the following:
var storeItem = db.StoreItems.Find(id); storeItem.ConceptID = viewModel.ConceptID; storeItem.Name = viewModel.Name; storeItem.Description = viewModel.Description; storeItem.StoreSubCategoryID = viewModel.StoreSubCategoryID; storeItem.RestaurantGLAccount = viewModel.RestaurantGLAccount; storeItem.MarketingGLAccount = viewModel.MarketingGLAccount; storeItem.SupplierInstructions = viewModel.SupplierInstructions; storeItem.SupplierScheduleID = viewModel.SupplierScheduleID; storeItem.Price = viewModel.Price; storeItem.StoreItemModifiers = StoreItemModifier.getModifiers(db, viewModel.SelectedModifiers); //if there was a file posted with the response, add it to the Item if (postedFile != null) { ... } db.SaveChanges();This code will add new modifiers to the item, but will not remove modifiers that are no longer selected, and will throw an exception if an existing modifier is left checked:
Violation of PRIMARY KEY constraint 'PK_dbo.StoreItemModifierAssignments'. Cannot insert duplicate key in object 'dbo.StoreItemModifierAssignments'.
IE:
Decker Dong ...
All-Star
118619 Points
18779 Posts
Re: Removing records from a one to zero or many relationship
Jan 25, 2013 12:01 AM|LINK
Hi,
A primary key cannot be duplicated and it must be unique. So you have to check whether your value to be inserted as the key is duplicated or not.
mgasparel
Member
298 Points
65 Posts
Re: Removing records from a one to zero or many relationship
Jan 25, 2013 12:13 AM|LINK
I'm curious... should EF handle updating these related entities, or am I supposed to manually update the StoreItemModifierAssignments records?
Decker Dong ...
All-Star
118619 Points
18779 Posts
Re: Removing records from a one to zero or many relationship
Jan 25, 2013 12:21 AM|LINK
Yes, but what I mean is that you cannot insert duplicated primary keys or unique ones;)
mgasparel
Member
298 Points
65 Posts
Re: Removing records from a one to zero or many relationship
Jan 25, 2013 12:28 AM|LINK
Yes, I understand. But what is happening is that instead of updating the existing records, EF is attempting to create NEW records (causing the PK violation)
I've tried several things, but can't seem to figure out how to get EF to handle updating the associations automatically.
Decker Dong ...
All-Star
118619 Points
18779 Posts
Re: Removing records from a one to zero or many relationship
Jan 25, 2013 12:42 AM|LINK
To create???
Why?
Have you written other SP to insert or Triggers?