EntityState set to modified after Submit

Jul 21, 2008 at 2:43 PM

Hi

I am pretty sure this question must have arised before, however when creating a new entity, setting it as CangeTrackingRoot and then Submitting it the entity is in modified state afterwards. I think EntityState.Original would be more appropriate, however this is not the fault of LinqToSqlEntityBase.

After further investigation i think this is due to Linq2Sql setting the key properties (for database generated key columns) and EntityBase then marks the entity as modified.

I am working on a fix that will allow Key Properties to be set without changing the entity state.

Jul 21, 2008 at 3:56 PM
Looks like i have found a fix. Already mailed it to mhunter. If anyone else's interested please contact me.
Jul 22, 2008 at 3:34 AM
Hi there Johannes,

Thanks for bug report - very much appreciated!

I've done a quick check and can confirm it's an issue, and yes it definately happens because of the key (generated column) being updated on brand new non-attached records.

I'll update the code witha fix (probably very similar to yours - thanks!) in the next day or so - i'll post here when done.

Thanks again, and if you find any other issues, be sure to let me know! :)

Matt
Jul 22, 2008 at 8:39 AM
Thanks for your fast response, keep on the good work.

Looks like it was more than a side effect to discover this bug while having some troubles with my design.

The issue is that when i am passing my entity to the Business Logic (or whatever) to persist it (e.g. create a context, syncronize, submit etc.), me as the user of the entity would assume its own EntityState and that of its children (aka entityTree) are updated accordingly, like the .NET DataSet did.

In the LINQEntityBaseExample this wouldnt work, but why?
It is because the entity is getting serialized accross the service, and thus not beeing the very same object when persisted to the database (object state is identical of course).
So the service works with it local copy, persists it and updates the LinqEntityState accordingy. These changes however will not reflect back over the service, so the users assumption is wrong.

If i try to persist the very same entity again this brings me in a lot of trouble....

The only solution i found so far is changing the service so it takes the ModifiedCustomer as ref, because then .NET will manage remote object access for me (so the physical identity of the object is the same on all endpoints).
I tried to research what cost this behaviour would incur and as

http://blogs.msdn.com/mjm/archive/2005/05/12/417035.aspx

states this should be avoided, even though i do not clearly understand why and until now i didnt find any other information about that subject.


So what do you think is the way to go in an 'SOA' (dont like that buzzzzzzword, so maybe just think of a tiered application) after i have persisted my entity, should my Logic return a new customer like:
customer = CustomerBus.Persist(customer)

or should clients do it like you did in your demo:
CustomerBus.Persist(customer);
customer = RetrieveCustomer.ById(customer.id);


Another issue is that even when passing the customer by the service so i do have the correct state after sync, my deleted entities are now detached.
When triggering an update again, LinqEntityBase tries to Attach them to the context. It does this for modified || detached entites.

Removing the "|| detached" in the synconizeWithDataContext() method leads to the second update succeeding,  producing no DBLog (thats what it should!);
However after the second update the detached entities are no longer part of the EntityTree so it look like:

Before 1st: Deleted
After 1st: Detached
After 2nd: Non existant

What should be done about that?
Jul 23, 2008 at 12:31 PM
In the "CustomerBus.Persist(customer)" case, I always go for the safest bet which is to return the object - then you know for sure what your doing.  In the old remoting protocol, there were issues with ref parameters in that it didn't really work and so you had to return the object.

It's up to you, if ref's working then these not really any difference.  For me though, I like to play it safe and return the new state of the object from the far end ;)

BTW.

Implenting your change right now - it's exactly what I would have typed  :)

Code change should be up soon.

Cheers

Matt.
Jul 23, 2008 at 2:06 PM
Happy to hear that! Your definately right about the remote object. Id even say that it might perform better to pass the object back... However i branched myself a new version of LINQEntityBase, as i was still expecting issues with deleted entities (see above). I removed the detached state and child entities can only be deleted via removing them from their collections or unwiring their references (whats the same in the end). I left SetAsDeleteOnSubmit in, it now only acts on root entities. If your interested i can share my version with you, however i dont have much time to explain as im working on an important project right now. For the future i want to optimize LEB with a factory that caches the reflection results, so i dont have to reflect every time i create a new object as this might be a bottleneck. Also usign a Set (must implement one myself) for the entity tracking might have some advances (less error checkin necessary etc.) Kind Regards Johannes