views:

554

answers:

4

I have an MVC2 app where I am starting to use the STE's. I am looking for some clarification on how updates should work.

Background:

If I have a Blog entity with related category entities and Related post/comment entities. In MVC I am rendering a view with the main Blog entity and the categories but not the related posts. When I post back the Blog entity to the server I can see the related categories but not the posts (since they were not in the view) in the entity being serialized back to the server. Also, the Blog entity has a change state of 'Added'.

I then try to call Applychanges() and SaveChanges() on this Blog entity to the perform an update and it fails because of the FK relationship with posts and the fact that there are related posts in the database but not attached to the entity I am sending back.

With some further testing...If I grab a current instance of the Blog entity (with all the related FK entities) while connected to the server (state=unchanged), modify a property (state=Modified) and update it works as expected.

So my questions: If I have related entities that are not being rendered in a view and therefore not post back with the Blog entity should the update work?

Why does the Blog entity get post back with an 'Added' status and not 'Modified'? I would assume it would come back with a 'Modified' changedstate for all changed entities and then when I called ApplyChanges/SaveChanges() only the modified items would attempt to update and this is why I would not need all related entities.

Should I be able to pass an entity directly from the client and ApplyChanges()/SaveChanges() or should I be posting back to the server the entity, grabbing an existing copy from the database, applying changes to that copy and then posting the existing object back?

A: 

We struggled with very similar issues--surrounding updates. Based on the information out there we gathered that STE is not ready for production, but did consider using them.

Anyway, the issues here center around the distinction between attached and detached, and the interaction between the ObjectStateManager and the STEs.. in the example you describe that does work, it works because it's attached the whole time, and the STE never actually transitions to using its STE behavior (this only happens after being deserialized to the client, or they get re-attached to an attached entity).

In answer to why they show up as added:

For instance, when STEs are instantiated, change tracking is deactivated and the default state in the change tracker is Added.

I find this all confusing, and interviews with Julia Lerman, and posts online, seem to indicate that the current STE release isn't ready for the real world...

See this response from Diego Vega (EF Team)

When you use STEs in this mode, they behave roughly as plain POCO objects. For example, you can manipulate the graph directly or use the APIs in the ObjectContext and ObjectStateManager, and you have to call DetectChanges to make sure that the state manager is in sync with the graph at any point before calling SaveChanges.

Most importantly, the standard Object Services API is not aware of STEs and so, such methods as AcceptAllChanges (which is the one that in your example is called implicitly during SaveChanges and resets the ObjectStateManager state for the complaint object to Unchanged) have absolutely no impact on the state stored by the STEs.

http://social.msdn.microsoft.com/Forums/en/adonetefx/thread/557e6db0-51df-45e5-a2e9-c31995969554

Hope this helps

Bobby
@Bobby thanks, I did see the same article from Diego when I was researching yesterday. But he states "STEs get into self-tracking mode only when: a. they are deserialized into the client ..." Which means to me that when the object is pulled from my WCF service and deserialized to the client it should start the tracking mode. This should pull it in UnModified state. I dont see the benefit of using STE's if it doesn't do this for me. It just provides some additional tracking of state (which doesn't really work with stateless environment :)
Jay
A: 

I don't believe I have ever said STEs are not ready for the real world. They just won't be for everyone. They are a pretty good tool for the dataset/datatable users who just want something that will work as easily. For these users (and there are a lot of them out there) putting the STE entities in the client app is not an evil thing. THey probably already own both sides of the pipe.

Julie Lerman
Hey Julie, welcome to Stack Overflow. I found your book to be very useful even if it does not cover EF 4 (STE, etc.) it still holds true for all EF concepts.
Tri Q
Well, why we do things in hard way when simple solution is in place.
ashraf
+1  A: 

As to your first problem:

I then try to call Applychanges() and SaveChanges() on this Blog entity to the perform an update and it fails because of the FK relationship with posts and the fact that there are related posts in the database but not attached to the entity I am sending back.

This could possibly be caused by your second issue ("Added" state instead of "Modified"). The Context may be trying to add the Blog instead of trying to save the changes, hence a FK constraint error.

As for your second question:

Why does the Blog entity get post back with an 'Added' status and not 'Modified'? I would assume it would come back with a 'Modified' changedstate for all changed entities and then when I called ApplyChanges/SaveChanges() only the modified items would attempt to update and this is why I would not need all related entities.

The issue to consider is "are you using the same type generated code on server and client"? STE have been known to not keep track of changes when you use data-service metadata generated types. For STE, there is an important piece of code that gets activated in the constructor that does not persist through the metadata generated types and hence is th cause of this problem.

And as for your last quesiton:

Should I be able to pass an entity directly from the client and ApplyChanges()/SaveChanges() or should I be posting back to the server the entity, grabbing an existing copy from the database, applying changes to that copy and then posting the existing object back?

Yes, it is possible (I have tested this) to ApplyChanges()/SaveChanges() to entities coming directly from the client, regardless of where the entity originally came from (from the server to be modified or created on the client as a new entity to be added).

Tri Q
I am going to mark this as the answer because you did provide some good feedback that was relevant. The overall answer though is that this will not work as I expected with MVC. I received a response from Diego Vega on the EF team explaining the reasons. Here is a link to his response:http://social.msdn.microsoft.com/Forums/en-US/adonetefx/thread/cecdc8b4-3e1f-46ec-93fe-fd44f42fea9c/#fb8a242b-c8f2-4ac2-a28c-4b948cac8c8c
Jay
A: 

My observation with this was that, while STE's in EF4 work well in situations where the client is stateful, they don't work as expected in a stateless environment.

MVC highlights this shortcoming. For example, lets take a typical entity "User" and a typical scenario, the EditController and the Edit view.

When we go to our database (get user, start tracking, return) or our service (change tracking automatically turns on after deserialization), the entity behaves as expected within the controller and the view.

However, when the Post comes back, the entity that our Controller method gets is a new entity and not the one that was given to us on the Get request. So this entity has no change tracking, is in the Added state, and will blow our database up if we treat it as the same instance that was handed to us on the Get phase.

Currently, you can mark the EF4 STE as modified, apply changes and save when the entity is truly new or just marked incorrectly as Added. That's about all you can do right now to support this scenario. Unless the MVC team comes up with a better pattern to support STEs or unless you change the default behavior of the model binder when instantiating the model to cache the entity instance...

Will