1

I have problems updating a child object of my POCO with CodeFirst. My POCO's are the following

public class Place { public int ID { get; set; public string Name { get; set; } public virtual Address Address { get; set; } } public class Address { public int ID { get; set; public string AddressLine { get; set; } public string City { get; set; } public virtual State State { get; set; } } public class State { public int ID { get; set; public string Name { get; set; } } 

I have a view to edit all fields of place and its childs. All properties are textbox except for State that is a DropDownList.

When user clicks so save button the view returns all Place properties filled, except State that is filled only with ID because it's value come from a DropDownList and Name is empty.

In Edit Post Method I have the following code:

if (ModelState.IsValid) { bool isNewPlace = place.ID == -1; //Hack, State name is empty from View, we reload place.Address.State = new StateBLL().GetByID(place.Address.State.ID); new PlaceBLL().Update(place); return RedirectToAction("Index"); } 

And Update code from PlaceBLL class is the following

protected override void Update(Place place) { MyDbContext.Instance().Set<Address>().Attach(place.Address); MyDbContext.Instance().Entry(place.Address).State = System.Data.EntityState.Modified; MyDbContext.Instance().Set<State>().Attach(place.Address.State); MyDbContext.Instance().Entry(place.Address.State) = System.Data.EntityState.Modified; MyDbContext.Instance().SaveChanges(); } 

When the user edit Place object all fields are update correctly except state, when the user change the state of some place, this change isn't persisted to database, if seems that Code first not detects state change from user.

Do you know why code first doesn't detect State change value from a Place?

Thanks.

1
  • 1
    Your update method seems pretty crazy. Do you have a good reason not to use basic EF to do this, ie select -> modify -> saveChanges? Commented Dec 27, 2012 at 23:09

2 Answers 2

1

Your Update method updates the (scalar properties of) Address and it updates the (scalar properties of) State but it doesn't update the relationship between place and Address (which is not a problem because you apparently only edit Address properties in your view without assigning another Address entity to place) and it doesn't update the relationship between place.Address and place.Address.State. But this is what you actually have changed in your view.

To update the relationship between place.Address and place.Address.State you have two options:

  • Introduce a foreign key property into your Address class that represents the FK to the state (this type of association is called Foreign Key Association):

    public class Address { public int ID { get; set; public string AddressLine { get; set; } public string City { get; set; } public int StateID { get; set; } public virtual State State { get; set; } } 

    Then make sure that you bind your dropdown list to place.Address.StateID (and not place.Address.State.ID). The FK property StateID will be populated with the new selected ID from the dropdown list when you post the view to the server. In your Update method you can remove then the third and fourth line. Updating the Address alone will also update the StateID foreign key. You also can remove the code the loads the State in your Edit Post action.

  • If you want to keep your current Independent Association (= association without exposed foreign key property in your model class) you must load the original state from the database and update it with the new state:

    protected override void Update(Place place) { var dbPlace = MyDbContext.Instance().Places.Include(p => p.Address.State) .Single(p => p.ID == place.ID); // Update scalar properties of place MyDbContext.Instance().Entry(dbPlace) .CurrentValues.SetValues(place); // Update scalar properties of Address MyDbContext.Instance().Entry(dbPlace.Address) .CurrentValues.SetValues(place.Address); // Change relationship between Adress and State if (dbPlace.Address.State.ID != place.Address.State.ID) { MyDbContext.Instance().States.Attach(place.Address.State); dbPlace.Address.State = place.Address.State; } MyDbContext.Instance().SaveChanges(); } 

    Again, you can remove the code the loads the State in your Edit Post action because the correct key property (State.ID) is enough to change a relationship.

Sign up to request clarification or add additional context in comments.

Comments

0

You also need to attach the Entity. Below is a simplistic version of what you need to do.

var updated = _dbSet.Attach(item); _dataContext.Entry(item).State = EntityState.Modified; return updated; 

5 Comments

Why is necessary to do it? If I undertand well code first is suposed that it track automatically all changes ? Why is necessary to specify than one child object of Place has changed?
@MarcCals Because the Entity needs to be attached with an Added or Modified for EF to produce a query to the database.
Looking better at your code this is the same I'm doing with MyDbContext.Instance().Set<State>().Attach(place.Address.State); MyDbContext.Instance().Entry(place.Address.State) = System.Data.EntityState.Modified; Is it true?
Can you post MyDbContext ..not sure what the .Instance Method is doing . Possibly contexts are different since you are newing up ProvinceBLL and PlaceBLL ..
MyDBContext.Instance() is a singleton that return a unique instance of DBContext during a Http Request. Sorry ProvinceBLL is a incorrect name for the class, it has to be StateBLL.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.