24

I transfer data between the entity framework and the business layer and user layer by using Data Transfer Objects. I do have some doubt, if I retrieve an object which is converted to a DTO, how do I update the correct object in the entity framework and not just insert a duplicate?

Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
user75278
  • 241
  • 1
  • 2
  • 3

5 Answers5

28

The following code will update an EF 4 entity that has been created as a controller parameter in MVC from a strongly typed view:

It seems the trick is to use the ObjectStateManager to change the state from Added to Modified once the entity has been added to the context.

MyEntities db = new MyEntities();
db.Product.AddObject(product);
db.ObjectStateManager.ChangeObjectState(product, System.Data.EntityState.Modified);
return db.SaveChanges() > 0;

As per @Sean Mills comment if you are using EF5 use:

 ((IObjectContextAdapter) db).ObjectContext.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Added);
Rob
  • 10,004
  • 5
  • 61
  • 91
  • Finally! I've wasted so much time with other workarounds - this works awesome without need to do dbObject.Property = passedObject.Property for every property when updating. – nikib3ro Feb 28 '13 at 00:09
  • 2
    if the ObjectStateManager is not a property of your context try ((System.Data.Entity.Infrastructure.IObjectContextAdapter)db).ObjectContext http://stackoverflow.com/a/8968643/678338 – politus May 30 '13 at 17:19
7

an old question, but just in case someone needs a code solution:

http://www.mikesdotnetting.com/Article/110/ASP.NET-MVC-Entity-Framework-Modifying-One-to-Many-and-Many-to-Many-Relationships

Example:

public void EditArticle(
        Article article, string articleTypeId, string[] categoryId) 
{ 
  var id = 0; 
  Article art = de.ArticleSet 
                  .Include("ArticleTypes")
                  .Include("Categories")
                  .Where(a => a.ArticleID == article.ArticleID)
                  .First();

  var count = art.Categories.Count;
  for (var i = 0; i < count; i++)
  {
    art.Categories.Remove(art.Categories.ElementAt(i));
    count--;
  }
  foreach (var c in categoryId)
  {
    id = int.Parse(c);
    Category category = de.CategorySet
        .Where(ct => ct.CategoryID == id).First();
    art.Categories.Add(category);
  }

  art.Headline = article.Headline;
  art.Abstract = article.Abstract;
  art.Maintext = article.Maintext;
  art.DateAmended = DateTime.Now;

  art.ArticleTypesReference.EntityKey = new EntityKey(
                                          "DotnettingEntities.ArticleTypeSet", 
                                          "ArticleTypeID", 
                                          int.Parse(articleTypeId)
                                          );

  de.SaveChanges();
}
Ryan Lundy
  • 204,559
  • 37
  • 180
  • 211
Bart
  • 4,830
  • 16
  • 48
  • 68
4
//I am replacing player :)
public ActionResult ProductEdit(string Id, Product product)
{
    int IdInt = DecyrptParameter(Id);
    MyEntities db = new MyEntities();

    var productToDetach = db.Products.FirstOrDefault(p=> p.Id == IdInt);
    if (product == null)
        throw new Exception("Product already deleted"); //I check if exists, maybe additional check if authorised to edit
    db.Detach(productToDetach);

    db.AttachTo("Products", product);
    db.ObjectStateManager.ChangeObjectState(product, System.Data.EntityState.Modified);

    db.SaveChanges();
    ViewData["Result"] = 1; // successful result
    return View();
}
Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
asdf_enel_hak
  • 7,474
  • 5
  • 42
  • 84
2

This should work for EF 5: https://stackoverflow.com/a/11749716/540802:

db.Entry(product).State = EntityState.Modified;
Community
  • 1
  • 1
Yevgen Safronov
  • 3,977
  • 1
  • 27
  • 38
2

You would need to include a primary or alternate key in the DTO, then match that key back to the correct EF entity upon update.

John Saunders
  • 160,644
  • 26
  • 247
  • 397