locked
OData client for Windows Phone doesn't keep one-to-many relationships in sync RRS feed

  • Question

  • I've got a simple entity data model kind of like this, where each person can give 0 or more donations:

    Person ( PersonId, PersonName )

    Donation ( DonationId, PersonId, AmountGiven, DateGivenOn )

    The Windows Phone development tools automatically generate client-size classes that have the expected properties, including a "Donations" collection on each Person object and a "Person" property on each Donation. I've noticed some strange behavior:

    (1) If you update the PersonId property on a specific Donation, the corresponding Person property on that donation is not changed. So at that point, Donation.Person.PersonId does NOT equal Donation.PersonId. Not good! However if you update the Person property on a specific Donation, the corresponding PersonId on that donation is changed, as expected. (Follow up 10/13: I can't reproduce this behavior; it seems that setting the Person property has no effect on the Donation.PersonId, so they can easily get out of sync.)

    (2) If you create a new Donation d and set the donor as Person p, then p.Donations does NOT automatically include d. Not Good! So when you add a new object you've got to remember to update both the 1 and many sides of the data model.

    (3) If you download data without using the .Include / .Expand clause in your query, the navigation property relationships are always null / empty. I would have hoped that if you downloaded all Person, and then downloaded all Donation using the same data context, that the navigation properties would be set properly.

    My complaint is that the default oData client is kind of tricky to use. If you use the navigation properties, you've got to remember to always set and update the navigation property (and not the foreign key), and also remember to update both sides of the relationship. And if you don't use .Include/.Expand queries, you've got to manually set all the navigation properties after the download completes. Am I doing something wrong here, or is this how it is supposed to be?

    I vaguely remember that the automatically generated oData client for Windows Silverlight is smarter and that it handles 1, 2, and 3 as you would expected.


    • Edited by JustinMag Friday, October 14, 2011 12:55 AM
    Thursday, October 6, 2011 12:15 AM

Answers

  • The OData client for Windows Phone should behave in basically the same way as the WCF Data Services client library for Silverlight. You may have noticed that DataServiceContext is a lightweight context and (unless using binding collections) you must manually report all changed entities and relationships to the context before changes can be sent to the data service. This can be especially confusing when you are used to using ObjectContext or DbContext in Entity Framework, which not only track changes but do the relationship fix-ups for you.

    The one exception to this is using the DataServiceCollection<T> binding collection.

    Let me address your specific points:

    1) It is true that you must manually notify the DataServiceContext when relationships between entities are created, updated, or deleted, otherwise the property values themselves can get out-of-sync and the context won't know to send updates to the data service when SaveChanges is called. The exception to this is when you load returned entities into a DataServiceCollection<T>. This binding collection (which inherits from ObservableCollection<T>) automatically reports objects added to or changed in the collection, when tracking is enabled. For an example of how to use a binding collection with tracking in a Windows Phone app, see How to: Consume an OData Service for Windows Phone.

    2) When using a binding collection with tracking, you can just call the following to create the relationship link and add the new donation too.

    somePerson.Donations.Add(newDonation)
    

    If you only set the reference, you bypass the nice reporting in DataServiceCollection<T> and need to do it all yourself (both set the object properties and reporting to the context).

    3) When you are using binding collections, it is better to either get the data at once using Expand() in the query or else load each related collection like this:

    somePerson.Donations.LoadAsync()
    

    This ensures that the links between Person and Donation are also tracked in the context. As I mentioned before, DataServiceContext doesn't do relationship fix-up like in EF.

    My advice is to use DataServiceCollection<T> as much as possible, which makes sense for Windows Phone apps that are all about binding anyway. The best approach is to define a ViewModel that exposes the DataServiceCollection<T> properties for binding. For an example of this approach, see Walkthrough: Consuming OData with MVVM for Windows Phone.

    Cheers,

    Glenn Gailey


    Please visit my blog

    This posting is provided "AS IS" with no warranties, and confers no rights.
    Sunday, October 16, 2011 7:52 AM

All replies

  • Hi JustinMag,

    Welcome!

    We will do some more pending research  about your problem and come back as soon as possible, Thanks for understanding.
    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, October 7, 2011 8:40 AM
    Moderator
  • The OData client for Windows Phone should behave in basically the same way as the WCF Data Services client library for Silverlight. You may have noticed that DataServiceContext is a lightweight context and (unless using binding collections) you must manually report all changed entities and relationships to the context before changes can be sent to the data service. This can be especially confusing when you are used to using ObjectContext or DbContext in Entity Framework, which not only track changes but do the relationship fix-ups for you.

    The one exception to this is using the DataServiceCollection<T> binding collection.

    Let me address your specific points:

    1) It is true that you must manually notify the DataServiceContext when relationships between entities are created, updated, or deleted, otherwise the property values themselves can get out-of-sync and the context won't know to send updates to the data service when SaveChanges is called. The exception to this is when you load returned entities into a DataServiceCollection<T>. This binding collection (which inherits from ObservableCollection<T>) automatically reports objects added to or changed in the collection, when tracking is enabled. For an example of how to use a binding collection with tracking in a Windows Phone app, see How to: Consume an OData Service for Windows Phone.

    2) When using a binding collection with tracking, you can just call the following to create the relationship link and add the new donation too.

    somePerson.Donations.Add(newDonation)
    

    If you only set the reference, you bypass the nice reporting in DataServiceCollection<T> and need to do it all yourself (both set the object properties and reporting to the context).

    3) When you are using binding collections, it is better to either get the data at once using Expand() in the query or else load each related collection like this:

    somePerson.Donations.LoadAsync()
    

    This ensures that the links between Person and Donation are also tracked in the context. As I mentioned before, DataServiceContext doesn't do relationship fix-up like in EF.

    My advice is to use DataServiceCollection<T> as much as possible, which makes sense for Windows Phone apps that are all about binding anyway. The best approach is to define a ViewModel that exposes the DataServiceCollection<T> properties for binding. For an example of this approach, see Walkthrough: Consuming OData with MVVM for Windows Phone.

    Cheers,

    Glenn Gailey


    Please visit my blog

    This posting is provided "AS IS" with no warranties, and confers no rights.
    Sunday, October 16, 2011 7:52 AM