locked
CancelEdit works incorrectly for newly created associations RRS feed

  • Question

  • I have an entity A with an association to an entity B using a foreign key BId.

    If I call a.CancelEdit() on an entity "a" of type A, then a.B is not correctly reset if the corresponding B entity is newly created.

    B existingB = ctx.Bs.First(); // obtained through a ctx.Load(ctx.GetBsQuery());
    B newB = new B {Id = -1};
    
    a.B = existingB; // First example with an existing entity. This example works as expected
    ((IEditableObject)a).BeginEdit();
    a.B = newB;
    ((IEditableObject)a).CancelEditEdit();
    Debug.Assert(a.BId == existingB.Id); // Succeeds 
    Debug.Assert(a.B == existingB); // Succeeds
    
    a.B = newB; // Second example with a new entity. This example fails
    ((IEditableObject)a).BeginEdit();
    a.B = existingB;
    ((IEditableObject)a).CancelEditEdit();
    Debug.Assert(a.BId == newB.Id); // Succeeds !!
    Debug.Assert(a.B == newB); // Fails a.B == null 
    

    Is this a known issue? Does anyone have a workaround?

    Friday, October 8, 2010 4:29 PM

Answers

  • Unfortunately it is rather problematic if such issues exist with newly created entities because it seems to imply that there are several limitations of RIA for manipulating new entities.

    It used to be worse, it used to be that even temporary keys or GUIDs were being ignored making imports of "new" entities very difficult. A future change that makes it possible to make temporary keys mandatory with the correct attributes would be even better, hope that happens. Would be even better if a built in temporary key system was put in place.

    This brings me to the topic of using IEditableObject  functionality.

    Very simple rule here. Do not expect any Entity functionality that is hidden behind an interface to be fully implemented and ready for all edge scenarios. The interfaces themselves and the logic implementing them have been designed to support specific UI controls and scenarios. If you know exactly what the interface does and you know it matches you scenario that is fine, but in other case you are better off implementing your own logic.

    Wednesday, October 13, 2010 9:20 AM

All replies

  • Unless you are using composition, the addition of a new EntityB is not considered a change to EntityA. It is a change to EntityB and therefore not affected by CancelEdit. More to the point, since you are familiar with RIA Services Contrib, CancelEdit is equivalent to Entity.ApplyState(null, Entity.SavedState) where BeginEdit is equivalent to Entity.SavedState = Entity.ExtractState(ExtractType.CurrentState).
    Friday, October 8, 2010 5:01 PM
  • Colin, maybe I miss the point, but the thing is that A holds the reference to B (I mean, A has a property BId). So setting a.B to newB (or existingB) does change the entity a. Do you mean that despite of this, changing a.BId is not considered a change to a??

    Moreover, my example shows that although in both cases a.BId is reset correctly, only in the first example is a.B also reset correctly. Since relationship span should connect existingB or newB to entity a (given the foreign key property a.BId), I suspect that something is going wrong.

    Friday, October 8, 2010 5:21 PM
  • There is some special handling in EntityRef/EntityCollection for New entities. Basically when running the filter predicate for an association member against the source EntitySet, New entities are filtered out. We took this approach because often the ID members for New entities are store generated, meaning on the client they don't have values yet. Using the default values to determine collection membership is problematic. For example in the classic Order/OrderDetail scenario, if you've newed up a bunch of Orders and Details, each detail would match each and every Order! In the future we have plans to flow additional metadata to the client indicating which members are "store generated" and that might allow us to relax this behavior a bit.

    Friday, October 8, 2010 9:00 PM
  • As a follow up, I'll clarify that when I say New entities are filtered out, that is only when the filter predicate is run to find matching entities from the EntitySet. Of course if you've explicitly added entities, those remain cached in the collection. That's normal usage path - new up the entities, hook them up and Submit. Your scenario above with the intervening association modification severs the association, and based on what I've said that association must be repaired manually. I expect its pretty rare to be making reference assignments in a BeginEdit session - the main use for those APIs is auto-binding forms, and usually such forms don't allow you to modify associations or FKs.

    Friday, October 8, 2010 9:15 PM
  • Colin, maybe I miss the point, but the thing is that A holds the reference to B (I mean, A has a property BId). So setting a.B to newB (or existingB) does change the entity a. Do you mean that despite of this, changing a.BId is not considered a change to a??

    Ah, sorry I was answering that from my IPad and it wasn't displaying your example code at the time. I was just going from the text of your question.

    Friday, October 8, 2010 11:57 PM
  • Mathew, thanks a lot for these insights!

    Unfortunately it is rather problematic if such issues exist with newly created entities because it seems to imply that there are several limitations of RIA for manipulating new entities.

    In our application we must be able to create and modify complex graphs of entities. We need to modify existing and newly created entities simultaneously. It is unacceptable to call submit changes on newly created entities just to get consistent behavior with existing entities. Amongst others, this is because creating new entities will not be a guarantee that they also will end up in our database, because modifications to graphs of entities can be canceled. So, it is crucial that using existing or newly created entities is as transparent as possible. It would really be a show stopper if RIA can't get operations on newly created entities work correctly and consistent with existing entities.

    This brings me to the topic of using IEditableObject  functionality. We are looking for a way to support cancellation of edit operations in our application. It looks like IEditableObject is intended for that. In our case we have dialogs that bind to multiple entities as well as dialogs that allow creating references between  entities. It's really unfortunate that CancelEdit does not support correct cancellation of created references. Why could the implementation of BeginEdit/CancelEdit not  save/restore the values of properties with the AssociationAttribute (in stead of the foreign key property values) in case the associated entities are new? This does not seem too complicated to implement.

    If IEditableObject is not the right way to go for supporting cancellation in our application (you seem to suggest this), is there an alternative solution that I can use to support cancellation?


    Monday, October 11, 2010 5:41 AM
  • Unfortunately it is rather problematic if such issues exist with newly created entities because it seems to imply that there are several limitations of RIA for manipulating new entities.

    It used to be worse, it used to be that even temporary keys or GUIDs were being ignored making imports of "new" entities very difficult. A future change that makes it possible to make temporary keys mandatory with the correct attributes would be even better, hope that happens. Would be even better if a built in temporary key system was put in place.

    This brings me to the topic of using IEditableObject  functionality.

    Very simple rule here. Do not expect any Entity functionality that is hidden behind an interface to be fully implemented and ready for all edge scenarios. The interfaces themselves and the logic implementing them have been designed to support specific UI controls and scenarios. If you know exactly what the interface does and you know it matches you scenario that is fine, but in other case you are better off implementing your own logic.

    Wednesday, October 13, 2010 9:20 AM