Raha
Raha

Reputation: 1969

Problem with SaveChanges() Entity Framework 4.1

I am having problem with saving the changes to database.

I am updating the model A in my controller, however when I save the changes using SaveChanges() I end up having a duplicated item in database for B.

After the UpdateModel() is called I inspected the Bs property and it was as I expected however right after the SaveChanges() is called if I inspect the Bs property I will see that the Id is completely different (new Id and new entry).

My class is similar to this:

public class A
{
    [HiddenInput(DisplayValue = false)]
    public int AId { get; set; }

    public string Name { get; set; }

    public virtual ICollection<B> Bs{ get; set; }
}

public class B
{
    [HiddenInput(DisplayValue = false)]
    public int BId { get; set; }

    public string Name { get; set; }

    public virtual ICollection<A> As{ get; set; }
}

My Controller is like this :

    [HttpPost]
    public ActionResult Edit(A theA)
    {
        try
        {
           db.Entry(theA).State = EntityState.Modified;

           foreach (var item in theA.Bs)
           {
               db.Entry(item).State = EntityState.Modified;
           }

           db.SaveChanges();

           return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

Am I doing something wrong ?

Thanks in advance

Upvotes: 2

Views: 6310

Answers (1)

Ladislav Mrnka
Ladislav Mrnka

Reputation: 364299

That is common behavior. The problem is that EF doesn't know that you attached an existing B so it automatically inserts a new record. You must say EF that the B is existing one by calling:

// here add B to the collection in the A and after that call:
dbContext.Entry<B>(someB).State = EntityState.Unchanged();

or by attaching B before you add it to collection in A (I'm not sure if this is possible when using UpdateModel in ASP.NET MVC).

dbContext.Bs.Attach(someB);
// now add B to the collection in the A

Other possibility is to load B from database first and add loaded object to the collection in A but it is additional roundtrip to database.

int id = someB.Id;
var loadedB = dbCotnext.Bs.Single(b => b.Id == id);
someA.Bs.Add(loadedB);
dbContext.As.Add(someA);
dbContext.SaveChanges();

Conclusion: Every time you call Add the whole object graph is tracked as inserted unless you attach related entities first (before you add them to inserted parent - the 2nd and 3rd example) or unless you manually change the state of related entities back to unchanged after adding the parent. (the 1st example).

Upvotes: 8

Related Questions