Reputation: 1311
I have problem with updating existing entity in DB. I'm using Entity Framework Code First.
I have small program with calculation food.
My domain classes>
public class Unit
{
public int Id { get; set; }
public string Name { get; set; }
}
public abstract class Item
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Ingredient : Item
{
public virtual Unit Unit { get; set; }
public decimal Price { get; set; }
}
public class Recipe : Item
{
public virtual List<RecipeItem> Items { get; set; }
public double WeightCoocked { get; set; }
public bool IsAlsoIngredient { get; set; }
}
public class RecipeItem
{
public int Id { get; set; }
public virtual Item Item { get; set; }
public int Quantity { get; set; }
}
Note only that RecipeItem can be Ingredient but also Recipe, so I can include recipe into recipe.
I tried this kind of updates methods:
public void Update1(Recipe recipe)
{
if (recipe == null)
return;
var originalRecipe = DataContext.Recipes.FirstOrDefault(i => i.Id == recipe.Id);
if (originalRecipe == null)
return;
DataContext.Entry(originalRecipe).CurrentValues.SetValues(recipe);
DataContext.SaveChanges();
}
Update1 works, but my collection is not updated.
public void Update2(Recipe recipe)
{
if (recipe == null)
return;
var originalRecipe = DataContext.Recipes.FirstOrDefault(i => i.Id == recipe.Id);
if (originalRecipe == null)
return;
DataContext.Entry(originalRecipe).State = EntityState.Modified;
DataContext.SaveChanges();
}
Update1 works same like Update1 but if I change collection I got exception. I also tried put there this line
DataContext.Entry(originalRecipe.Items).State = EntityState.Modified;
Last Update method>
public void Update3(Recipe recipe)
{
if (recipe == null)
return;
var originalRecipe = DataContext.Recipes.FirstOrDefault(i => i.Id == recipe.Id);
if (originalRecipe == null)
return;
DataContext.Recipes.Attach(recipe);
DataContext.Entry(originalRecipe).State = EntityState.Modified;
DataContext.Entry(originalRecipe.Items).State = EntityState.Modified;
DataContext.SaveChanges();
}
Getting same exception: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
I have no problem with updating tables> Units and Ingredients but with collection makes me nervous. I already watched vidoes about EF on pluralsight but there is not example like I have.
Thank for your help.
Upvotes: 3
Views: 17844
Reputation: 4922
You're misusing what Entity Framework is built for. Generally it's a good idea to load an entity, modify it (letting the attached DbContext track the changes for you), then allow it to detect if changes have been made. If this isn't possible (which I will presume as you've asked this question), then your best bet is to map the properties of the entities from one object to another. You will need to do this for each entity in the related entities too.
public void Update(Recipe recipe)
{
if (recipe == null)
return;
var originalRecipe = DataContext.Recipes.SingleOrDefault(i => i.Id == recipe.Id);
if (originalRecipe == null)
return;
originalRecipe.Name= recipe.Name;
originalRecipe.WeightCooked = recipe.WeightCooked;
originalRecipe.IsAlsoIngredient = recipe.IsAlsoIngredient;
foreach(var item in recipe.Items)
{
var originalItem = DataContext.RecipeItems.SingleOrDefault(i=>i.Id == item.Id);
if(originalItem == null)
return;
originalItem.Quantity = item.Quantity;
...
}
DataContext.SaveChanges();
}
As an aside, I've used SingleOrDefault
instead of FirstOrDefault
.
If you want to do this mapping automatically then look at something like AutoMapper which allows you to map objects together.
Upvotes: 5
Reputation: 8726
Try this
public void Update1(Recipe recipe)
{
if (recipe == null)
return;
var originalRecipe = DataContext.Recipes.FirstOrDefault(i => i.Id == recipe.Id);
if (originalRecipe == null)
return;
originalRecipe.YOurPepertiNameToUpdate = recipe.YOurPepertiNameToUpdate ;
originalRecipe.YOurPepertiNameToUpdate1 = recipe.YOurPepertiNameToUpdate1;
originalRecipe.YOurPepertiNameToUpdate2 = recipe.YOurPepertiNameToUpdate2 ;
DataContext.SaveChanges();
}
Upvotes: 0