locked
Self Tracking entity and 2 references to the same table

    Question

  • Hello,

    I have one class with two references to the same table, the table is customers table and have Address1_ID and Address2_ID foreign key to the same table. The problem is that they can have the sames entity reference but the field is filled in different postback with diferent contexts. When i apply save changes i have the error message "item with same key...", i know that currently Selft tracking not support it but maybe can post what is the solution development team think of maybe any temporary solution :)

    Other problem can be when i have a sales header with some sales lines, if two of more of this sales lines have the same article when apply changes i can got the same error.

    Thanks for all, and sorry for my bad english.

    Monday, October 5, 2009 8:24 PM

Answers

  • Hi,

    Well, since we have fix-up logic in property setters for FKs and references, it is not always easy to set a reference to null and leave the corresponding FK property untouched. So, I still think perhaps the best approach would be to retrieve only SalesHeader/SalesLine and never actually set the reference to the Article instance.

    On the other side, I am assuming that you will probably want to establish relationships from SalesLines to articles that do not appear in the original SalesHeader/SalesLine graph, so it makes more sense to pre-load the articles in a separate request to the service. Also, you might want to maintain a dictionary of articles by key on the client, so that lookups become faster and you can actually maintain a single instance for each.

    Does it make sense?

    Thanks,
    Diego
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Wednesday, October 14, 2009 4:54 AM
    Moderator

All replies

  • Hello Wirlo,

    If I understand the issue correctly, what you are seeing is the expected behavior of the ApplyChanges extension method when the graph passed to it contains two separate instances with the same identity. We currently don't have plans to handle this situation in ApplyChanges, as there are variations in which we could see conflicting changes.

    Recent builds of EF 4 (post-beta 1) support Foreign Key associations, which allow you to manage relationships using FK properties. This might be of help in a case like this. For instance, for the SalesHeader/SalesLine/Article case, you could bring only information about the SalesHeader and the SalesLine, and only a FK property on SalesLine would indicate the corresponding Article. Then, you could preload the list of articles on the client and only specify the relationship between SalesLine and Articles using the FK value. This would avoid sending the Articles in the graph back to the server and of course would also avoid sending duplicates.

    Another possible workaround with beta 1 and CTP1 would be to walk the graph and re-assign all the instances with the same identity to a single instance. You can get the self-tracking entity to not consider this as a change by directly manipulating the data structures of the change tracker. Certainly this workaround would be more involved.

    Unfortunately, I don't think we have a better workaround at the moment.

    Thanks,
    Diego
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Tuesday, October 13, 2009 4:35 AM
    Moderator
  • Hello Diego,

    You understand the issue correctly, i think FK property can be the best solution. In the SalesHeader/SalesLine/Article the main idea is to load the SalesHeader with SalesLine and Articles using includes and can use SalesHeader.SalesLine.Article.Description to get the descripcion of the article, but if client load all references then when send back to the server it can fail because of the multiple instances. When beta2 will launch maybe can be a good idea to write a small method that "clean" the related object and keep the FK property before applychanges.
    Tuesday, October 13, 2009 7:29 AM
  • Hi,

    Well, since we have fix-up logic in property setters for FKs and references, it is not always easy to set a reference to null and leave the corresponding FK property untouched. So, I still think perhaps the best approach would be to retrieve only SalesHeader/SalesLine and never actually set the reference to the Article instance.

    On the other side, I am assuming that you will probably want to establish relationships from SalesLines to articles that do not appear in the original SalesHeader/SalesLine graph, so it makes more sense to pre-load the articles in a separate request to the service. Also, you might want to maintain a dictionary of articles by key on the client, so that lookups become faster and you can actually maintain a single instance for each.

    Does it make sense?

    Thanks,
    Diego
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Wednesday, October 14, 2009 4:54 AM
    Moderator
  • Diego,
    Can you please elaborate more on how to "...only specify the relationship between SalesLine and Articles using the FK value."

    Thanks,
    Aviv.
    Thursday, December 31, 2009 6:14 AM
  • Hello Aviv,

    What I mean is that you can simply assign the value of the primary key of the principal as the value of the FK property, for instance, to relate a product to a category, you could do as follows:

        product1.CategoryID = cagegory1.CategoryID;

    As opposed to establishing the relationship using a reference, which is done setting the navigation property:

        product1.Cagegory = category1;

    For certain disconnected scenarios the code above has some advantages, since it doesn't create a reference automatically you can still send around the product1 object without carrying the category1 object along with it. However, the CategoryID value on product1 already determines that there is a relationship so when you apply the product1 object back on the server the relationship is persisted in the database.

    Hope this helps,
    Diego
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Saturday, January 2, 2010 5:25 PM
    Moderator
  • Hello Diego,

     

    I am encountering this property in my solution and would like to ask if there was an alternative to this workaround. The reason that I need an alternative is as follows.

     

    1. I'm working with large amount of data therefor cannot afford to fetch related entities on separate calls to the data store.

    2. I cannot cache all data on client because the data set is simply too large.

    3. I need to use direct referencing because it affects the way the UI visualizes the data(ie. an entity with a collection of entities will be displayed by the UI and any add or delete to this collection must be reflected on the UI).

    4. Part of my solution requirements is to be able to undo any changes to an entity. My approach is to take snapshots (via serialization) and storing them in a history list which a user can then restore them at one stage.

    Also if the answer is no, then is there any plans to overcome this issue in the near future? How long can we expect to wait for an update in STE infrastructures?

    Thank you in advance.

    Tri Q.

    Friday, July 30, 2010 8:23 AM
  • If I understand the issue correctly, what you are seeing is the expected behavior of the ApplyChanges extension method when the graph passed to it contains two separate instances with the same identity. We currently don't have plans to handle this situation in ApplyChanges, as there are variations in which we could see conflicting changes.


    We are having a similar problem with self-tracking entities and frankly foreign key associations are a no-go area as far as we're concerned. I do understand the notion of possible conflicting changes. But why not support multiple separate instances of the same identity where the identity hasn't been changed? I would like to have seen the detection of multiple separate instances of the same identity that are in fact changed. Unchanged instances should be irrelevant to the object tracker and in effect be semantically the same as foreign keys. In our situation we make sure that multiple separate instances of the same identity in one object graph are never changed.

    Furthermore we are running into this problem when we 'overwrite' a navigation property with a separate instance of the same (unchanged) property. So we have something a long the lines of an object of class X that has a navigation property to an object of class Y. When we retrieve an instance of class X through one context and retrieve the instance of class Y that belongs the object of class X through a different context, we're getting the exact same error when we set the navigation property to be the retrieved instance of the same identity Y. The error occurs when ApplyChanges is called.

    At the moment we're considering copying changes from the new graph to the existing graph. Obviously this is not an ideal solution but we want a generic solution and a nice and clean object model without fiddling with foreign keys. As it is now, STE seem to be only suitable for simple object models.

    Thursday, August 5, 2010 3:05 PM
  • I'm adding a bit of sample code to clarify the 2nd paragraph of my previous post. It's not :

    // retrieve actions and users through a factory.
    List<Action> actions = actionFactory.GetActions();
    List<User> users = userFactory.GetUsers(); 
    // single out a specific action
    Actie action = actions.Where(a => a.Id == 1).Single();
    // single out a specific user. This user happens to be the user that is linked to action with Id=1
    User user = users.Where(g => g.Id == 2).Single();
    // start tracking changes on the action
    action.StartTracking();
    // set a property to mark the action as modified
    action.Deadline="2010/08/06";
    // set the user for the action (this might happen 'for real' as a result of updating an action through a grid for example)
    // the user is a separate instance of the existing user
    action.User = user; 
    // apply changes
    using(var ctx = new MyContext())
    {
      ctx.Actions.ApplyChanges(action); // error occurs: AcceptChanges cannot continue because the object's key values 
                       // conflict with another object in the ObjectStateManager. Make sure that the key 
                       // values are unique before calling AcceptChanges
      ctx.SaveChanges();
    }
    Friday, August 6, 2010 8:46 AM
  • Any chance of a response to my questions?

    1. Why can't I update a navigation property with the same identity instantiated through a different context?
    2. Why not allow multiple instances of the same identity in one object graph where only one instance at most is changed while all others are unchanged?

    Tuesday, August 10, 2010 8:26 AM