views:

51

answers:

1

Hi Guys,

I have an Entity Framework 4.0 model implemented with pure POCO's (no code generation, no self-tracking entities, just plain old CLR objects).

Now, here is some code i have in my UI to perform an UPDATE:

[HttpPost]
public ActionResult UpdatePerson(Person person)
{
    repository.Attach(person);
    unitOfWork.Commit();
}

Essentially, i have an Action Method which accepts a strongly-typed Person object, and i need to UPDATE this entity.

Doesn't error, but also doesn't persist the changes to the DB either. :(

When i inspect the EntityState during the "Commit" of my Unit of Work:

var entities = ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged);

I see my entity, with EntityState.Unchanged.

So that explains why it has not been persisted. My Find,Add,Delete operations are working fine (persisting correctly). But UPDATE doesn't seem to work.

I've found some threads saying i need to manually set the object state:

ctx.ObjectStateManager.ChangeObjectState(person, EntityState.Modified);

Is that correct? Where would i put this logic? Expose as an operation on my Unit of Work?

Obviously the issue is i have no change tracking whatsoever, due to the use of Pure POCO's (no EntityObject derivation, no INotifyPropertyChanging implementation).

But i haven't found an issue with it until now.

What am i doing wrong?

+1  A: 

Well, since you don't have any change tracking, etc., there should be a way for EF to determine what to do with the attached entity when SaveChanges() is called. By default, the EntityState is Unchanged, so if you want to Update, you have to manually set the state.

Another way would be to query for the Person with this Id, rewrite the properties with the data you fetch from the controller, and call SaveChanges(). This is a safer way actually, since you can guard yourself from a situation where the Person gets deleted while the user is editing the webform; but this obviously requires an extra roundtrip to the DB, which is often less desirable.

In any case, I would have a repository Update() method (more specific than Attach), that would actually attach the entity and change the EntityState to Modified. And you still have relatively clean code in your Action:

public ActionResult UpdatePerson(Person person)
{
    repository.Update(person);
    unitOfWork.Commit();
}
Yakimych
Yeah, i don't really want to do an extra round trip. So we have to manually set the EntityState (as i predicted). Cool, thanks. Also - i was thinking - is there a way the "Update" method can be smart enough to figure out if it's an UPDATE or an INSERT? (ie check the PersonId, if its > 0, it's an UPDATE, else an INSERT?) or is that too crazy/scary. Would be nice if the one method could handle both scenarios. Possible?
RPM1984
As far as I understand, you are talking about the `Update()` method you are to create, so you can make it as smart as you would like ;) E.g. Attach entity, then do the check `if (Person.Id == 0) { /* change state to Added */ } else { /* Change state to Modified */ }`. I am not sure it's a great idea, though. Having separate methods for inserting and updating is generally more readable. Why would you want to merge them into one?
Yakimych
Because i'm using MVC, and the operation of adding/modifying a Person entity is the same (HTTP POST, pass through strongly typed object). So i have no way of knowing if it's an add or update (of course, i could pass through an extra flag). I agree though, i'll seperate them out, might have to pass through hidden field in HTTP POST stating it's an add/update. Thanks
RPM1984