views:

170

answers:

2

Hey all, I have two functions in a SL project (VS2010) that do almost exactly the same thing, yet one throws an error and the other does not. It seems to be related to the projections, but I am unsure about the best way to resolve.

The function that works is...

public void LoadAllChunksExpandAll(DataHelperReturnHandler handler, string orderby)
    {
        DataServiceCollection<CmsChunk> data = null;

        DataServiceQuery<CmsChunk> theQuery = _dataservice
            .CmsChunks
            .Expand("CmsItemState")
            .AddQueryOption("$orderby", orderby);

        theQuery.BeginExecute(
            delegate(IAsyncResult asyncResult)
            {
                _callback_dispatcher.BeginInvoke(
                        () =>
                        {
                            try
                            {
                                DataServiceQuery<CmsChunk> query = asyncResult.AsyncState as DataServiceQuery<CmsChunk>;
                                if (query != null)
                                {
                                    //create a tracked DataServiceCollection from the result of the asynchronous query.
                                    QueryOperationResponse<CmsChunk> queryResponse =
                                        query.EndExecute(asyncResult) as QueryOperationResponse<CmsChunk>;
                                    data = new DataServiceCollection<CmsChunk>(queryResponse);

                                    handler(data);
                                }
                            }
                            catch
                            {
                                handler(data);
                            }
                        }
                    );
            },
            theQuery
        );
    }

This compiles and runs as expected. A very, very similar function (shown below) fails...

             public void LoadAllPagesExpandAll(DataHelperReturnHandler handler, string orderby)
    {
        DataServiceCollection<CmsPage> data = null;

        DataServiceQuery<CmsPage> theQuery = _dataservice
            .CmsPages
            .Expand("CmsChildPages")
            .Expand("CmsParentPage")
            .Expand("CmsItemState")
            .AddQueryOption("$orderby", orderby);

        theQuery.BeginExecute(
            delegate(IAsyncResult asyncResult)
            {
                _callback_dispatcher.BeginInvoke(
                        () =>
                        {
                            try
                            {
                                DataServiceQuery<CmsPage> query = asyncResult.AsyncState as DataServiceQuery<CmsPage>;
                                if (query != null)
                                {
                                    //create a tracked DataServiceCollection from the result of the asynchronous query.
                                    QueryOperationResponse<CmsPage> queryResponse = query.EndExecute(asyncResult) as QueryOperationResponse<CmsPage>;
                                    data = new DataServiceCollection<CmsPage>(queryResponse);

                                    handler(data);
                                }
                            }
                            catch
                            {
                                handler(data);
                            }
                        }
                    );
            },
            theQuery
        );
    }

Clearly the issue is the Expand projections that involve a self referencing relationship (pages can contain other pages). This is under SL4 or SL3 using ADONETDataServices SL3 Update CTP3.

I am open to any work around or pointers to goo information, a Google search for the error results in two hits, neither particularly helpful that I can decipher.

The short error is "An item could not be added to the collection. When items in a DataServiceCollection are tracked by the DataServiceContext, new items cannot be added before items have been loaded into the collection."

The full error is...

System.Reflection.TargetInvocationException was caught Message=Exception has been thrown by the target of an invocation. StackTrace: at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters) at System.Data.Services.Client.ClientType.ClientProperty.SetValue(Object instance, Object value, String propertyName, Boolean allowAdd) at System.Data.Services.Client.AtomMaterializer.ApplyItemsToCollection(AtomEntry entry, ClientProperty property, IEnumerable items, Uri nextLink, ProjectionPlan continuationPlan) at System.Data.Services.Client.AtomMaterializer.ApplyFeedToCollection(AtomEntry entry, ClientProperty property, AtomFeed feed, Boolean includeLinks) at System.Data.Services.Client.AtomMaterializer.MaterializeResolvedEntry(AtomEntry entry, Boolean includeLinks) at System.Data.Services.Client.AtomMaterializer.Materialize(AtomEntry entry, Type expectedEntryType, Boolean includeLinks) at System.Data.Services.Client.AtomMaterializer.DirectMaterializePlan(AtomMaterializer materializer, AtomEntry entry, Type expectedEntryType) at System.Data.Services.Client.AtomMaterializerInvoker.DirectMaterializePlan(Object materializer, Object entry, Type expectedEntryType) at System.Data.Services.Client.ProjectionPlan.Run(AtomMaterializer materializer, AtomEntry entry, Type expectedType) at System.Data.Services.Client.AtomMaterializer.Read() at System.Data.Services.Client.MaterializeAtom.MoveNextInternal() at System.Data.Services.Client.MaterializeAtom.MoveNext() at System.Linq.Enumerable.d_b11.MoveNext() at System.Data.Services.Client.DataServiceCollection1.InternalLoadCollection(IEnumerable1 items) at System.Data.Services.Client.DataServiceCollection1.StartTracking(DataServiceContext context, IEnumerable1 items, String entitySet, Func2 entityChanged, Func2 collectionChanged) at System.Data.Services.Client.DataServiceCollection1..ctor(DataServiceContext context, IEnumerable1 items, TrackingMode trackingMode, String entitySetName, Func2 entityChangedCallback, Func2 collectionChangedCallback) at System.Data.Services.Client.DataServiceCollection1..ctor(IEnumerable1 items) at Phinli.Dashboard.Silverlight.Helpers.DataHelper.<>c__DisplayClass44.<>c__DisplayClass46.<LoadAllPagesExpandAll>b__43() InnerException: System.InvalidOperationException Message=An item could not be added to the collection. When items in a DataServiceCollection are tracked by the DataServiceContext, new items cannot be added before items have been loaded into the collection. StackTrace: at System.Data.Services.Client.DataServiceCollection1.InsertItem(Int32 index, T item) at System.Collections.ObjectModel.Collection`1.Add(T item) InnerException:

Thanks for any help!

A: 

This sounds a little like a bug in Data Services.

I'll follow up with the Data Services Team and get back to you with an answer.

Might take a couple of days because of the weekend.

Alex James

Data Services PM

Alex James
I appreciate you guys looking into it, please let me know what you find!
Soulhuntre
A: 

I think the issue here is that the DataServiceCollection is failing to add the downloaded entities into the corresponding DataServiceCollection properties of the top level CMSPage types.We do some special casing to make sure that the DataServiceCollection can only be used after its started tracking some objects. I'll investigate this later, meanwhile try this code instead :

public void LoadAllPagesExpandAll(DataHelperReturnHandler handler, string orderby) 
{ 
  DataServiceCollection<CmsPage> data = new   DataServiceCollection<CmsPage>( _dataservice );

  DataServiceQuery<CmsPage> theQuery = _dataservice 
      .CmsPages 
      .Expand("CmsChildPages") 
      .Expand("CmsParentPage") 
      .Expand("CmsItemState") 
      .AddQueryOption("$orderby", orderby); 

  theQuery.BeginExecute( 
      delegate(IAsyncResult asyncResult) 
      { 
    _callback_dispatcher.BeginInvoke( 
      () => 
      { 
          try 
          { 
        DataServiceQuery<CmsPage> query = asyncResult.AsyncState as DataServiceQuery<CmsPage>; 
        if (query != null) 
        { 
            //create a tracked DataServiceCollection from the result of the asynchronous query. 
            QueryOperationResponse<CmsPage> queryResponse = query.EndExecute(asyncResult) as QueryOperationResponse<CmsPage>; 
            data.Load(queryResponse); 

            handler(data); 
        } 
          } 
          catch 
          { 
        handler(data); 
          } 
      } 
        ); 
      }, 
      theQuery 
  ); 
} 
Phani Raj
Thanks for looking into it... sadly no, still the same exception at the same point.
Soulhuntre