Пример #1
0
        /// <summary>
        /// Executes SaveChanges on the specified context and with the default options and verifies the results.
        /// </summary>
        /// <param name="verifier">The verifier to use for verification.</param>
        /// <param name="contextData">The data for the context.</param>
        /// <param name="context">The context to verify SaveChanges on.</param>
        /// <returns>The response from SaveChanges</returns>
        public static DSClient.DataServiceResponse VerifySaveChanges(this ISaveChangesVerifier verifier, DataServiceContextData contextData, DSClient.DataServiceContext context)
        {
            ExceptionUtilities.CheckArgumentNotNull(verifier, "verifier");
            ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData");
            ExceptionUtilities.CheckArgumentNotNull(context, "context");

            return verifier.VerifySaveChanges(contextData, context, null);
        }
Пример #2
0
        public void FilterCollectionWithAnyAll()
        {
            DataServiceContext ctx = new DataServiceContext(new Uri("http://localhost"), ODataProtocolVersion.V4);

            var values = ctx.CreateQuery<EntityWithCollections>("Values");
            var testCases = new[]
            {
                new{
                    q = from e in values
                        where e.CollectionOfInt.Any()
                        select e,
                    url = "Values?$filter=CollectionOfInt/any()"
                },
                new{
                    q = from e in values
                        where e.CollectionOfInt.Any() && e.ID == 0
                        select e,
                    url = "Values?$filter=CollectionOfInt/any() and ID eq 0"
                },
                new{
                    q = from e in values
                        where e.CollectionOfInt.Any(mv => mv == 2 )
                        select e,
                    url = "Values?$filter=CollectionOfInt/any(mv:mv eq 2)"
                },
                new{
                    q = from e in values
                        where e.CollectionOfInt.Any(mv => mv > e.ID ) && e.ID <100
                        select e,
                    url = "Values?$filter=CollectionOfInt/any(mv:mv gt $it/ID) and ID lt 100"
                },
                new{
                    q = from e in values
                        where e.CollectionOfComplexType.Any(mv => e.CollectionOfString.All(s => s.StartsWith(mv.Name)) || e.ID <100) && e.ID > 50
                        select e,
                    url = "Values?$filter=CollectionOfComplexType/any(mv:$it/CollectionOfString/all(s:startswith(s,mv/Name)) or $it/ID lt 100) and ID gt 50"
                },
                new{
                    q = from e in values
                        where e.CollectionOfComplexType.All(mv => mv.Name.StartsWith("a") || e.ID <100) && e.ID > 50
                        select e,
                    url = "Values?$filter=CollectionOfComplexType/all(mv:startswith(mv/Name,'a') or $it/ID lt 100) and ID gt 50"
                },
                new{
                    q = from e in values
                        where e.CollectionOfComplexType.All(mv => mv.Name.Contains("a") || mv.Numbers.All(n=>n % 2 == 0)) && e.ID/5 == 3
                        select e,
                    url = "Values?$filter=CollectionOfComplexType/all(mv:contains(mv/Name,'a') or mv/Numbers/all(n:n mod 2 eq 0)) and ID div 5 eq 3"
                },
            };

            TestUtil.RunCombinations(testCases, (testCase) =>
            {
                Assert.AreEqual(ctx.BaseUri.AbsoluteUri + testCase.url,testCase.q.ToString(), "url == q.ToString()");
            });
        }
Пример #3
0
        /// <summary>
        /// Executes SaveChanges on the specified context and with specified options and verifies the results.
        /// </summary>
        /// <param name="verifier">The verifier to use for verification.</param>
        /// <param name="contextData">The data for the context.</param>
        /// <param name="context">The context to verify SaveChanges on.</param>
        /// <param name="options">The options for saving changes.</param>
        /// <returns>The response from SaveChanges</returns>
        public static DSClient.DataServiceResponse VerifySaveChanges(this ISaveChangesVerifier verifier, DataServiceContextData contextData, DSClient.DataServiceContext context, SaveChangesOptions? options)
        {
#if SILVERLIGHT
            throw new TaupoNotSupportedException("Not supported in Silverlight");
#else
            ExceptionUtilities.CheckArgumentNotNull(verifier, "verifier");
            ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData");
            ExceptionUtilities.CheckArgumentNotNull(context, "context");

            DSClient.DataServiceResponse response = null;
            SyncHelpers.ExecuteActionAndWait(c1 => verifier.VerifySaveChanges(c1, contextData, context, options, (c2, r) => { response = r; c2.Continue(); }));
            return response;
#endif
        }
        /// <summary>
        /// Tracks the SaveChanges method.
        /// </summary>
        /// <param name="data">The data service context data on which to apply state transition.</param>
        /// <param name="options">The options.</param>
        /// <param name="response">The response.</param>
        /// <param name="cachedOperationsFromResponse">The individual operation respones, pre-enumerated and cached.</param>
        /// <param name="tracker">The entity data change tracker to use</param>
        public static void TrackSaveChanges(this DataServiceContextData data, SaveChangesOptions options, DSClient.DataServiceResponse response, IEnumerable<DSClient.OperationResponse> cachedOperationsFromResponse, IEntityDescriptorDataChangeTracker tracker)
        {
            ExceptionUtilities.CheckArgumentNotNull(data, "data");
            ExceptionUtilities.CheckArgumentNotNull(response, "response");
            ExceptionUtilities.CheckArgumentNotNull(cachedOperationsFromResponse, "cachedOperationsFromResponse");
            ExceptionUtilities.CheckArgumentNotNull(tracker, "tracker");

            // Check options and response consistency
            if ((options & SaveChangesOptions.ContinueOnError) == 0)
            {
                ExceptionUtilities.Assert(response.Count(r => r.Error != null) == 0, "Check save changes options and response consistency: no errors in the response when ContinueOnError is off.");
            }

            // because some links will not have separate requests, we need to keep track of all link changes
            var allPendingLinkChanges = data.GetOrderedChanges().OfType<LinkDescriptorData>().ToList();

            // go through the pending changes and update the states based on whether the request succeeded
            foreach (DSClient.ChangeOperationResponse changeResponse in cachedOperationsFromResponse)
            {
                DescriptorData descriptorData;
                LinkDescriptorData linkDescriptorData = null;
                StreamDescriptorData streamDescriptorData = null;
                var entityDescriptor = changeResponse.Descriptor as DSClient.EntityDescriptor;
                if (entityDescriptor != null)
                {
                    descriptorData = data.GetEntityDescriptorData(entityDescriptor.Entity);
                }
                else
                {
                    var linkDescriptor = changeResponse.Descriptor as DSClient.LinkDescriptor;
                    if (linkDescriptor != null)
                    {
                        linkDescriptorData = data.GetLinkDescriptorData(linkDescriptor.Source, linkDescriptor.SourceProperty, linkDescriptor.Target);
                        descriptorData = linkDescriptorData;
                        allPendingLinkChanges.Remove(linkDescriptorData);
                    }
                    else
                    {
#if WINDOWS_PHONE
                        throw new TaupoNotSupportedException("Stream Descriptors are not supported on Windows Phone");
#else
                        // for stream descriptors, we need to find the parent descriptor, then get the stream descriptor data from it                        
                        var streamDescriptor = (DSClient.StreamDescriptor)changeResponse.Descriptor;
                        
                        entityDescriptor = streamDescriptor.EntityDescriptor;
                        streamDescriptorData = data.GetStreamDescriptorData(entityDescriptor.Entity, streamDescriptor.StreamLink.Name);
                        descriptorData = streamDescriptorData;
#endif
                    }
                }

                // don't update states for responses that indicate failure
                if (changeResponse.Error != null)
                {
                    continue;
                }

                // because the request succeeded, make the corresponding updates to the states
                if (descriptorData.State == EntityStates.Deleted ||
                        (linkDescriptorData != null &&
                        linkDescriptorData.State == EntityStates.Modified &&
                        linkDescriptorData.SourceDescriptor.State == EntityStates.Deleted))
                {
                    data.RemoveDescriptorData(descriptorData);
                }
                else
                {
                    // for non-deleted descriptors, we need to update states based on the headers
                    var entityDescriptorData = descriptorData as EntityDescriptorData;
                    if (entityDescriptorData != null)
                    {
                        if (entityDescriptorData.IsMediaLinkEntry && entityDescriptorData.DefaultStreamState == EntityStates.Modified)
                        {
                            entityDescriptorData.DefaultStreamDescriptor.UpdateFromHeaders(changeResponse.Headers);
                            entityDescriptorData.DefaultStreamState = EntityStates.Unchanged;
                        }
                        else
                        {
                            if (entityDescriptorData.IsMediaLinkEntry && entityDescriptorData.DefaultStreamState == EntityStates.Added)
                            {
                                entityDescriptorData.DefaultStreamState = EntityStates.Unchanged;
                            }

                            // because there might have been a reading-entity event for this entity, we need to apply the headers through the tracker
                            tracker.TrackUpdateFromHeaders(entityDescriptorData, changeResponse.Headers);

                            // ensure that all updates are applied before moving to the next response
                            tracker.ApplyPendingUpdates(entityDescriptorData);

                            entityDescriptorData.ParentForInsert = null;
                            entityDescriptorData.ParentPropertyForInsert = null;
                            entityDescriptorData.InsertLink = null;
                        }
                    }
                    else if (streamDescriptorData != null)
                    {
                        streamDescriptorData.UpdateFromHeaders(changeResponse.Headers);
                    }

                    descriptorData.State = EntityStates.Unchanged;
                }
            }

            // go through each link change that did not have an assocatiated response and update its state
            foreach (var linkDescriptorData in allPendingLinkChanges.OfType<LinkDescriptorData>())
            {
                if (linkDescriptorData.State == EntityStates.Added || linkDescriptorData.State == EntityStates.Modified)
                {
                    linkDescriptorData.State = EntityStates.Unchanged;
                }
            }
        }
        /// <summary>
        /// Calculates the expected response from DataServiceContext.SaveChanges based on the context data before saving changes.
        /// Assumes there are no errors in the response.
        /// </summary>
        /// <param name="dataBeforeSaveChanges">The data before saving changes.</param>
        /// <param name="options">The options for saving changes.</param>
        /// <param name="context">The DataServiceContext instance which is calling SaveChanges.</param>
        /// <returns><see cref="DataServiceResponseData"/> that expresses expectations for the response.</returns>
        public DataServiceResponseData CalculateSaveChangesResponseData(DataServiceContextData dataBeforeSaveChanges, SaveChangesOptions options, DSClient.DataServiceContext context)
        {
            ExceptionUtilities.CheckArgumentNotNull(dataBeforeSaveChanges, "dataBeforeSaveChanges");
            ExceptionUtilities.CheckArgumentNotNull(context, "context");

            DataServiceResponseData responseData = new DataServiceResponseData();

            responseData.IsBatchResponse = options == SaveChangesOptions.Batch;

            bool hasChanges = false;

            // Note: ordering is important as changes should be processed in the order specified by user.
            foreach (DescriptorData descriptorData in dataBeforeSaveChanges.GetOrderedChanges())
            {
                int statusCode = (int)HttpStatusCode.NoContent;

                var entityDescriptorData = descriptorData as EntityDescriptorData;
                if (entityDescriptorData != null)
                {
                    if (entityDescriptorData.IsMediaLinkEntry && entityDescriptorData.DefaultStreamState == EntityStates.Modified)
                    {
                        responseData.Add(new ChangeOperationResponseData(descriptorData) { StatusCode = statusCode });
                    }

                    if (descriptorData.State == EntityStates.Added)
                    {
                        statusCode = GetStatusCodeForInsert(context);

                        if (entityDescriptorData.IsMediaLinkEntry)
                        {
                            responseData.Add(new ChangeOperationResponseData(descriptorData) { StatusCode = statusCode });
                            statusCode = GetStatusCodeForUpdate(context);
                        }
                    }
                    else if (descriptorData.State == EntityStates.Modified)
                    {
                        statusCode = GetStatusCodeForUpdate(context);
                    }
                    else if (descriptorData.State != EntityStates.Deleted)
                    {
                        continue;
                    }
                }

                var linkDescriptorData = descriptorData as LinkDescriptorData;
                if (linkDescriptorData != null && (linkDescriptorData.State == EntityStates.Added || linkDescriptorData.State == EntityStates.Modified))
                {
                    if (!linkDescriptorData.WillTriggerSeparateRequest())
                    {
                        continue;
                    }
                }

                responseData.Add(new ChangeOperationResponseData(descriptorData) { StatusCode = statusCode });
                hasChanges = true;
            }

            if (responseData.IsBatchResponse)
            {
                responseData.BatchStatusCode = hasChanges ? (int)HttpStatusCode.Accepted : 0;
            }
            else
            {
                responseData.BatchStatusCode = -1;
            }

            return responseData;
        }
        private static int GetStatusCodeForUpdate(DSClient.DataServiceContext context)
        {
            DataServiceResponsePreference preference = DataServiceResponsePreference.Unspecified;
#if !WINDOWS_PHONE
            preference = context.AddAndUpdateResponsePreference.ToTestEnum();
#endif
            if (preference == DataServiceResponsePreference.IncludeContent)
            {
                return (int)HttpStatusCode.OK;
            }
            else
            {
                return (int)HttpStatusCode.NoContent;
            }
        }
Пример #7
0
        public void AnyAllClientVersionTests()
        {
            TestUtil.RunCombinations(ServiceVersion.DataServiceProtocolVersions, maxProtocolVersion =>
            {
                DataServiceContext ctx = new DataServiceContext(new Uri("http://localhost"), maxProtocolVersion);

                var movies = ctx.CreateQuery<Movie>("Movies");
                var testCases = new[]
                {
                    new{
                        q = from m in movies
                            where m.Awards.Any()
                            select m,
                        ErrorMessage = "Error translating Linq expression to URI: The method 'Any' is not supported when MaxProtocolVersion is less than '4.0'."
                    },
                    new{
                        q = from m in movies
                            where m.Awards.Any(a => a.ID == 2)
                            select m,
                        ErrorMessage = "Error translating Linq expression to URI: The method 'Any' is not supported when MaxProtocolVersion is less than '4.0'."
                    },
                    new{
                        q = from m in movies
                            where m.Titles.Any(t => t.Contains("Space"))
                            select m,
                        ErrorMessage = "Error translating Linq expression to URI: The method 'Any' is not supported when MaxProtocolVersion is less than '4.0'."
                    },
                    new{
                        q = from m in movies
                            where m.Actors.OfType<MegaStar>().Any()
                            select m,
                        ErrorMessage = "Error translating Linq expression to URI: The method 'OfType' is not supported when MaxProtocolVersion is less than '4.0'."
                    },
                    new{
                        q = from m in movies
                            where m.Director.Awards.All(a => a.Movie == m)
                            select m,
                        ErrorMessage = "Error translating Linq expression to URI: The method 'All' is not supported when MaxProtocolVersion is less than '4.0'."
                    },
                };

                TestUtil.RunCombinations(testCases, testCase =>
                {
                    string qstr = testCase.q.ToString();
                    if (maxProtocolVersion < ODataProtocolVersion.V4)
                    {
                        Assert.AreEqual(testCase.ErrorMessage, qstr, "ErrorMessage == qstr");
                    }
                    else
                    {
                        Assert.IsTrue(qstr.Contains("any(") || qstr.Contains("all("), "qstr should contain any(...) or all(...)");
                    }
                });
            });
        }
Пример #8
0
        public void FilterNavigationWithAnyAll()
        {
            DataServiceContext ctx = new DataServiceContext(new Uri("http://localhost"), ODataProtocolVersion.V4);
            ctx.ResolveName = (type) =>
                                  {
                                      return "NS." + type.Name;
                                  };

            var movies = ctx.CreateQuery<Movie>("Movies");
            var testCases = new[]
            {
                new{
                    q = from m in movies
                        where m.Awards.Any()
                        select m,
                    url = "Movies?$filter=Awards/any()"
                },
                new{
                    q = from m in movies
                        where m.Awards.Any() && m.ID == 0
                        select m,
                    url = "Movies?$filter=Awards/any() and ID eq 0"
                },
                new{
                    q = from m in movies
                        where m.Awards.Any(a => a.ID == 2)
                        select m,
                    url = "Movies?$filter=Awards/any(a:a/ID eq 2)"
                },
                new{
                    q = from m in movies
                        where m.Awards.Any(a => a.ID == m.ID)
                        select m,
                    url = "Movies?$filter=Awards/any(a:a/ID eq $it/ID)"
                },
                new{
                    q = from m in movies
                        where m.Director.Awards.All(a => a.Movie == m)
                        select m,
                    url = "Movies?$filter=Director/Awards/all(a:a/Movie eq $it)"
                },
                new{
                    q = from m in movies
                        where m.Actors.Any(a => a.DirectedMovies.All(dm => dm == m))
                        select m,
                    url = "Movies?$filter=Actors/any(a:a/DirectedMovies/all(dm:dm eq $it))"
                },
                new{
                    q = from m in movies
                        where m.Actors.Any(a => a.DirectedMovies.All(dm => dm == m && m.Awards.All(aw=>aw.Movie.Director == dm.Director)))
                        select m,
                    url = "Movies?$filter=Actors/any(a:a/DirectedMovies/all(dm:dm eq $it and $it/Awards/all(aw:aw/Movie/Director eq dm/Director)))"
                },
                new{
                    q = from m in movies
                        where m.Actors.Any(a => a is MegaStar)
                        select m,
                    url = "Movies?$filter=Actors/any(a:isof(a, 'NS.MegaStar'))"
                },
                new{
                    q = from m in movies
                        where m.Awards.All(aw => aw.Movie.Director is MegaStar)
                        select m,
                    url = "Movies?$filter=Awards/all(aw:isof(aw/Movie/Director, 'NS.MegaStar'))"
                },
                new{
                    q = from m in movies
                        where m.Awards.All(aw => m.Director is MegaStar && !aw.Movie.Actors.Any(a=> a is MegaStar))
                        select m,
                    url = "Movies?$filter=Awards/all(aw:isof($it/Director, 'NS.MegaStar') and not aw/Movie/Actors/any(a:isof(a, 'NS.MegaStar')))"
                },
                new{
                    q = from m in movies
                        where m.Awards.All(aw => m.Director.FirstName.StartsWith("Hus") && !aw.Movie.Actors.Any(a=> a is MegaStar))
                        select m,
                    url = "Movies?$filter=Awards/all(aw:startswith($it/Director/FirstName,'Hus') and not aw/Movie/Actors/any(a:isof(a, 'NS.MegaStar')))"
                },
                new{
                    q = from m in movies
                        where m.Awards.All(aw => m.Director is MegaStar && ((MegaStar)m.Director).MegaStartProp.StartsWith("Hus") && aw.Recepient == m.Director)
                        select m,
                    url = "Movies?$filter=Awards/all(aw:isof($it/Director, 'NS.MegaStar') and startswith(cast($it/Director,'NS.MegaStar')/MegaStartProp,'Hus') and aw/Recepient eq $it/Director)"
                },
                new{
                    q = from m in movies
                        where m.Actors.OfType<MegaStar>().Any()
                        select m,
                    url = "Movies?$filter=Actors/NS.MegaStar/any()"
                },
                new{
                    q = from m in movies
                        where m.Actors.OfType<MegaStar>().Any( ms=> ms.Awards.Any())
                        select m,
                    url = "Movies?$filter=Actors/NS.MegaStar/any(ms:ms/Awards/any())"
                },
                new{
                    q = from m in movies
                        where m.Actors.OfType<MegaStar>().All( ms=> ms.Awards.Any())
                        select m,
                    url = "Movies?$filter=Actors/NS.MegaStar/all(ms:ms/Awards/any())"
                },
                new{
                    q = from m in movies
                        where m.Actors.All(a=> a is MegaStar && a.Awards.Any())
                        select m,
                    url = "Movies?$filter=Actors/all(a:isof(a, 'NS.MegaStar') and a/Awards/any())"
                },
                new{
                    q = from m in movies
                        where m.Actors.OfType<MegaStar>().All( ms=> ms.Awards.Any(a=> a.AwardDate > new DateTime(0, DateTimeKind.Utc) && ms.DirectedMovies.Any() && m.Director == ms))
                        select m,
                    url = "Movies?$filter=Actors/NS.MegaStar/all(ms:ms/Awards/any(a:a/AwardDate gt 0001-01-01T00:00:00Z and ms/DirectedMovies/any() and $it/Director eq ms))"
                },
                new{
                    q = from m in movies
                        where m.Actors.OfType<MegaStar>().All( ms=> ms.Awards.Any(a=> a.AwardDate > new DateTime(0, DateTimeKind.Utc) && ms.DirectedMovies.Any(dm=> dm.Awards.All(aw=> aw.Recepient.FirstName == ms.FirstName )) && m.Director == ms))
                        select m,
                    url = "Movies?$filter=Actors/NS.MegaStar/all(ms:ms/Awards/any(a:a/AwardDate gt 0001-01-01T00:00:00Z and ms/DirectedMovies/any(dm:dm/Awards/all(aw:aw/Recepient/FirstName eq ms/FirstName)) and $it/Director eq ms))"
                },
                new{
                    q = from m in movies
                        where m.Awards.Any(aw => aw.Recepient is MegaStar && m.Actors.OfType<MegaStar>().All(a=>a.DateOfBirth > new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc)))
                        select m,
                    url = "Movies?$filter=Awards/any(aw:isof(aw/Recepient, 'NS.MegaStar') and $it/Actors/NS.MegaStar/all(a:a/DateOfBirth gt 2010-01-01T00:00:00Z))"
                },
            };

            TestUtil.RunCombinations(testCases, (testCase) =>
            {
                Assert.AreEqual(ctx.BaseUri.AbsoluteUri + testCase.url, testCase.q.ToString(), "url == q.ToString()");
            });
        }
Пример #9
0
        /// <summary>
        /// Creates the data service context data from data service context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="maxProtocolVersion">The max protocol version.</param>
        /// <returns>DataServiceContextData based on context</returns>
        public static DataServiceContextData CreateDataServiceContextDataFromDataServiceContext(DSClient.DataServiceContext context, DataServiceProtocolVersion maxProtocolVersion)
        {
            var contextData = new DataServiceContextData(context.GetType(), maxProtocolVersion);

            // set all the properties on the context data to the values from the context
            foreach (var productProperty in typeof(DSClient.DataServiceContext).GetProperties(true, false))
            {
                var testProperty = typeof(DataServiceContextData).GetProperty(productProperty.Name, true, false);
                if (testProperty != null && testProperty.PropertyType.IsAssignableFrom(productProperty.PropertyType))
                {
                    var value = productProperty.GetValue(context, null);
                    testProperty.SetValue(contextData, value, null);
                }
            }

            return contextData;
        }