Exemple #1
30
        public void SingleChangesetShouldBeAtomic()
        {
            this.TestClientContext.MergeOption = MergeOption.OverwriteChanges;
            SaveChangesOptions[] options = new SaveChangesOptions[]
            {
                // All modifications share one changeset
                SaveChangesOptions.BatchWithSingleChangeset,

                // Each modification uses seperate changeset
                SaveChangesOptions.BatchWithIndependentOperations
            };

            Airline airline = new Airline()
            {
                Name = "American Delta",
                AirlineCode = "DL",
                TimeStampValue = new byte[] { 0 }
            };

            Airline airline1 = new Airline()
            {
                Name = "American Delta",
                AirlineCode = "DL",
                TimeStampValue = new byte[] { 0 }
            };

            Flight flight = new Flight()
            {
                ConfirmationCode = "JH58496",
                FlightNumber = "DL589",
                StartsAt = new DateTimeOffset(new DateTime(2014, 2, 10, 15, 00, 0)),
                EndsAt = new DateTimeOffset(new DateTime(2014, 2, 10, 16, 30, 0)),
                AirlineId = "DL",
                SeatNumber = "C32",
                FromId = "KSEA",
                ToId = "ZSSS",
                Airline = airline
            };

            foreach (var option in options)
            {
                this.TestClientContext.ResetDataSource().Execute();

                this.TestClientContext.AddToAirlines(airline);
                this.TestClientContext.AddToFlights(flight);
                // Post an entity with same ID, this would cause creation failture.
                this.TestClientContext.AddToAirlines(airline1);

                switch (option)
                {
                    case SaveChangesOptions.BatchWithIndependentOperations:
                        DataServiceResponse response1 = this.TestClientContext.SaveChanges(option);
                        Assert.Equal(200, response1.BatchStatusCode);
                        Assert.True(response1.IsBatchResponse);
                        Assert.Equal(3, response1.Count());
                        var result = response1.ToList();

                        // 3rd operation would fail, but new flight entry would be inserted.
                        Assert.Equal(201, result[0].StatusCode);
                        Assert.Equal(201, result[1].StatusCode);
                        Assert.Equal(500, result[2].StatusCode);
                        Assert.Equal(1,
                            this.TestClientContext
                                .Flights.Where(f => f.FlightNumber == flight.FlightNumber).ToList().Count);
                        break;
                    case SaveChangesOptions.BatchWithSingleChangeset:
                        bool exc = false;
                        try
                        {
                            // The single changeset would fail.
                            this.TestClientContext.SaveChanges(option);
                        }
                        catch (Exception)
                        {
                            exc = true;
                        }

                        Assert.True(exc);

                        Assert.Equal(0,
                            this.TestClientContext
                                .Flights.Where(f => f.FlightNumber == flight.FlightNumber).ToList().Count);
                        break;
                }


                this.TestClientContext.Detach(airline1);
                this.TestClientContext.Detach(airline);
                this.TestClientContext.Detach(flight);
            }
        }
        public void CreateRelatedEntitesWithDifferentChangesetOptions()
        {
            this.TestClientContext.MergeOption = MergeOption.OverwriteChanges;
            SaveChangesOptions[] options = new SaveChangesOptions[]
            {
                // All modifications share one changeset
                SaveChangesOptions.BatchWithSingleChangeset,

                // Each modification uses seperate changeset
                SaveChangesOptions.BatchWithIndependentOperations
            };

            Airline airline = new Airline()
            {
                Name = "American Delta",
                AirlineCode = "DL",
                TimeStampValue = new byte[] { 0 }
            };

            Flight flight = new Flight()
            {
                ConfirmationCode = "JH58496",
                FlightNumber = "DL589",
                StartsAt = new DateTimeOffset(new DateTime(2014, 2, 10, 15, 00, 0)),
                EndsAt = new DateTimeOffset(new DateTime(2014, 2, 10, 16, 30, 0)),
                AirlineId = "DL",
                SeatNumber = "C32",
                FromId = "KSEA",
                ToId = "ZSSS",
                Airline = airline
            };

            foreach (var option in options)
            {
                this.TestClientContext.ResetDataSource().Execute();

                // This should fail for BatchWithIndependentOperations, as the foreign key restriction breaks.
                this.TestClientContext.AddToFlights(flight);
                this.TestClientContext.AddToAirlines(airline);
                this.TestClientContext.SendingRequest2 += (sender, e) =>
                {
                    e.RequestMessage.SetHeader("Prefer", "odata.continue-on-error");
                };

                DataServiceResponse response1 = this.TestClientContext.SaveChanges(option);

                switch (option)
                {
                    case SaveChangesOptions.BatchWithIndependentOperations:
                        
                        Assert.Equal(200, response1.BatchStatusCode);
                        Assert.True(response1.IsBatchResponse);
                        Assert.Equal(2, response1.Count());
                        var result1 = response1.ToList();
                        // fail for adding flight, but succeed for adding airlire
                        Assert.Equal(500, result1[0].StatusCode);
                        Assert.Equal(201, result1[1].StatusCode);
                        Assert.Equal(0,
                            this.TestClientContext
                                .Flights.Where(f => f.FlightNumber == flight.FlightNumber).ToList().Count);
                        break;
                    case SaveChangesOptions.BatchWithSingleChangeset:
                        Assert.Equal(200, response1.BatchStatusCode);
                        Assert.True(response1.IsBatchResponse);
                        Assert.Equal(2, response1.Count());
                        var result2 = response1.ToList();

                        // Both would succeed
                        Assert.Equal(201, result2[0].StatusCode);
                        Assert.Equal(201, result2[1].StatusCode);

                        Assert.Equal(1,
                            this.TestClientContext
                                .Flights.Where(f => f.FlightNumber == flight.FlightNumber).ToList().Count);
                        break;

                }

                this.TestClientContext.Detach(airline);
                this.TestClientContext.Detach(flight);
            }
        }
        public void IfMatchCRUDTest()
        {
            this.TestClientContext.MergeOption = MergeOption.OverwriteChanges;

            // Post an entity
            Flight flight = new Flight()
            {
                ConfirmationCode = "JH44444",
                StartsAt = DateTimeOffset.Parse("2016-01-04T17:55:00+08:00"),
                EndsAt = DateTimeOffset.Parse("2016-01-04T20:45:00+08:00"),
                Duration = TimeSpan.Parse("2:50"),
                FlightNumber = "AA4035",
                FromId = "KJFK",
                ToId = "KORD",
                AirlineId = "AA"
            };

            this.TestClientContext.AddToFlights(flight);
            this.TestClientContext.SaveChanges();
            int flightId = flight.FlightId;
            var code = flight.ConfirmationCode;

            string etag = null;
            int statusCode = -1;
            EventHandler<ReceivingResponseEventArgs> statusCodeHandler = (sender, eventArgs) =>
            {
                etag = eventArgs.ResponseMessage.GetHeader("ETag");
                statusCode = eventArgs.ResponseMessage.StatusCode;
            };
            this.TestClientContext.ReceivingResponse += statusCodeHandler;

            // Retrieve a none match etag
            flight = this.TestClientContext.Flights.ByKey(new Dictionary<string, object>() { { "flightId", 1 } }).GetValue();
            var nonMatchEtag = etag;

            // Request single entity, the header should return Etag
            flight = this.TestClientContext.Flights.ByKey(new Dictionary<string, object>() { { "flightId", flightId } }).GetValue();
            Assert.Equal(code, flight.ConfirmationCode);
            Assert.NotNull(etag);
            Assert.Equal(200, statusCode);

            // Test If-Match header and the header is not matched, should return 412.
            EventHandler<SendingRequest2EventArgs> sendRequestEvent = (sender, eventArgs) =>
            {
                eventArgs.RequestMessage.SetHeader("If-Match", nonMatchEtag);
            };
            this.TestClientContext.SendingRequest2 += sendRequestEvent;
            try
            {
                flight = this.TestClientContext.Flights.ByKey(new Dictionary<string, object>() { { "flightId", flightId } }).GetValue();
            }
            catch (DataServiceQueryException)
            {
            }
            Assert.Equal(412, statusCode);

            // Test If-Match header and the header is matched, should return the entity.
            this.TestClientContext.SendingRequest2 -= sendRequestEvent;
            sendRequestEvent = (sender, eventArgs) =>
            {
                eventArgs.RequestMessage.SetHeader("If-Match", etag );
            };
            this.TestClientContext.SendingRequest2 += sendRequestEvent;
            flight = this.TestClientContext.Flights.ByKey(new Dictionary<string, object>() { { "flightId", flightId } }).GetValue();
            Assert.Equal(code, flight.ConfirmationCode);
            Assert.Equal(200, statusCode);
            var oldEtag = etag;

            // Update the Entity without If-Match header, should return 428
            // If this is not removed, client will auto add If-Match header
            var descriptor = this.TestClientContext.GetEntityDescriptor(flight);
            descriptor.ETag = null;
            this.TestClientContext.SendingRequest2 -= sendRequestEvent;
            code = "JH33333";
            flight.ConfirmationCode = code;
            this.TestClientContext.UpdateObject(flight);
            try
            {
                this.TestClientContext.SaveChanges();
            }
            catch (DataServiceRequestException)
            {
            }
            this.TestClientContext.Detach(flight);
            Assert.Equal(428, statusCode);

            // Query to get etag updated
            this.TestClientContext.SendingRequest2 -= sendRequestEvent;
            flight = this.TestClientContext.Flights.ByKey(new Dictionary<string, object>() { { "flightId", flightId } }).GetValue();

            // Update the Entity with If-Match not match, should return 412
            this.TestClientContext.SendingRequest2 -= sendRequestEvent;
            sendRequestEvent = (sender, eventArgs) =>
            {
                eventArgs.RequestMessage.SetHeader("If-Match", nonMatchEtag);
            };
            this.TestClientContext.SendingRequest2 += sendRequestEvent;
            code = "JH33333";
            flight.ConfirmationCode = code;
            this.TestClientContext.UpdateObject(flight);
            try
            {
                this.TestClientContext.SaveChanges();
            }
            catch (DataServiceRequestException)
            {
            }
            this.TestClientContext.Detach(flight);
            Assert.Equal(412, statusCode);

            // Query the flight again and etag should not be updated.
            this.TestClientContext.SendingRequest2 -= sendRequestEvent;
            flight = this.TestClientContext.Flights.ByKey(new Dictionary<string, object>() { { "flightId", flightId } }).GetValue();
            Assert.NotEqual(code, flight.ConfirmationCode);
            Assert.Equal(200, statusCode);
            Assert.Equal(oldEtag, etag);

            // Update the Entity with If-Match matches, should return 204
            this.TestClientContext.SendingRequest2 -= sendRequestEvent;
            sendRequestEvent = (sender, eventArgs) =>
            {
                eventArgs.RequestMessage.SetHeader("If-Match", etag);
            };
            this.TestClientContext.SendingRequest2 += sendRequestEvent;
            code = "JH33333";
            flight.ConfirmationCode = code;
            this.TestClientContext.UpdateObject(flight);
            this.TestClientContext.SaveChanges();
            this.TestClientContext.Detach(flight);
            Assert.Equal(204, statusCode);

            // Query the flight again and etag should be updated.
            this.TestClientContext.SendingRequest2 -= sendRequestEvent;
            flight = this.TestClientContext.Flights.ByKey(new Dictionary<string, object>() { { "flightId", flightId } }).GetValue();
            Assert.Equal(code, flight.ConfirmationCode);
            Assert.Equal(200, statusCode);
            Assert.NotEqual(oldEtag, etag);

            // Delete the Entity with If-Match does not match, should return 412
            this.TestClientContext.SendingRequest2 -= sendRequestEvent;
            sendRequestEvent = (sender, eventArgs) =>
            {
                eventArgs.RequestMessage.SetHeader("If-Match", nonMatchEtag);
            };
            this.TestClientContext.SendingRequest2 += sendRequestEvent;
            this.TestClientContext.DeleteObject(flight);
            try
            {
                this.TestClientContext.SaveChanges();
            }
            catch (DataServiceRequestException)
            {
            }
            Assert.Equal(412, statusCode);

            // Query to get etag updated
            this.TestClientContext.SendingRequest2 -= sendRequestEvent;
            flight = this.TestClientContext.Flights.ByKey(new Dictionary<string, object>() { { "flightId", flightId } }).GetValue();

            // Delete the Entity with If-Match matches, should return 204
            this.TestClientContext.SendingRequest2 -= sendRequestEvent;
            sendRequestEvent = (sender, eventArgs) =>
            {
                eventArgs.RequestMessage.SetHeader("If-Match", etag);
            };
            this.TestClientContext.SendingRequest2 += sendRequestEvent;
            this.TestClientContext.DeleteObject(flight);
            this.TestClientContext.SaveChanges();
            Assert.Equal(204, statusCode);

            // Query the flight again and entity does not exist.
            this.TestClientContext.SendingRequest2 -= sendRequestEvent;
            try
            {
                flight = this.TestClientContext.Flights.ByKey(new Dictionary<string, object>() { { "flightId", flightId } }).GetValue();
            }
            catch (DataServiceQueryException)
            {
            }
            Assert.Equal(404, statusCode);
        }
        public void CURDSingleNavigationPropertyAndRef()
        {
            this.TestClientContext.MergeOption = Microsoft.OData.Client.MergeOption.OverwriteChanges;

            Airline airline = new Airline()
            {
                Name = "American Delta",
                AirlineCode = "DL",
                TimeStampValue = new byte[] { 0 }
            };

            this.TestClientContext.AddToAirlines(airline);
            this.TestClientContext.SaveChanges();

            // Post an entity
            Flight flight = new Flight()
            {
                ConfirmationCode = "JH58496",
                FlightNumber = "DL589",
                StartsAt = new DateTimeOffset(new DateTime(2014, 2, 10, 15, 00, 0)),
                EndsAt = new DateTimeOffset(new DateTime(2014, 2, 10, 16, 30, 0)),
                AirlineId = null,
                SeatNumber = "C32",
                FromId = "KSEA",
                ToId = "ZSSS"
            };

            this.TestClientContext.AddToFlights(flight);
            this.TestClientContext.SaveChanges();

            // Set $ref
            this.TestClientContext.SetLink(flight, "Airline", airline);
            this.TestClientContext.SaveChanges();

            this.TestClientContext.Detach(airline);
            // Query an Navigation Property
            var airline2 = this.TestClientContext.Flights
                .ByKey(new Dictionary<string, object>() { { "FlightId", flight.FlightId } })
                .Airline.GetValue();
            Assert.Equal(airline.AirlineCode, airline2.AirlineCode);

            // Expand an Navigation Property
            var flight2 = this.TestClientContext.Flights
                .Expand(f => f.From)
                .Expand(f => f.To)
                .Where(f => f.FlightId == flight.FlightId)
                .SingleOrDefault();
            Assert.Equal(flight.FromId, flight2.From.IcaoCode);
            Assert.Equal(flight.ToId, flight2.To.IcaoCode);

            // Expand with select
            this.TestClientContext.Detach(flight2.From);
            var flight3 = this.TestClientContext.Flights
                .AddQueryOption("$expand", "From($select=IcaoCode)")
                .Where(f => f.FlightId == flight.FlightId)
                .SingleOrDefault();
            Assert.Equal(flight.FromId, flight3.From.IcaoCode);
            Assert.Null(flight3.From.IataCode);

            // Get $ref
            Dictionary<string, string> headers = new Dictionary<string, string>();
            ODataMessageReaderSettings readerSettings = new ODataMessageReaderSettings { BaseUri = this.TestClientContext.BaseUri };

            HttpWebRequestMessage request = new HttpWebRequestMessage(
                new DataServiceClientRequestMessageArgs(
                    "Get",
                    new Uri(string.Format(this.TestClientContext.BaseUri + "/Flights({0})/Airline/$ref", flight.FlightId),
                        UriKind.Absolute),
                    false,
                    false,
                    headers));

            using (HttpWebResponseMessage response = request.GetResponse() as HttpWebResponseMessage)
            {
                Assert.Equal(200, response.StatusCode);
                using (var stream = response.GetStream())
                {
                    StreamReader reader = new StreamReader(stream);
                    var expectedPayload = "{"
                        + @"  ""@odata.context"":""http://*****:*****@"""@odata.id"":""http://localhost:18384/api/Trippin/Airlines('{0}')""", airline2.AirlineCode)
                        + "}";
                    var content = reader.ReadToEnd();
                    Assert.Equal(expectedPayload.Replace(" ", ""), content);
                }
            }

            // Delete $ref
            this.TestClientContext.SetLink(flight, "Airline", null);
            this.TestClientContext.SaveChanges();

            this.TestClientContext.Detach(airline);

            HttpWebRequestMessage request2 = new HttpWebRequestMessage(
                new DataServiceClientRequestMessageArgs(
                    "Get",
                    new Uri(string.Format(this.TestClientContext.BaseUri + "/Flights({0})/Airline/$ref", flight.FlightId)
                        , UriKind.Absolute),
                    false,
                    false,
                    headers));

            DataServiceTransportException exception = null;

            try
            {
                request2.GetResponse();
            }
            catch (DataServiceTransportException e)
            {
                exception = e;
            }
            Assert.NotNull(exception);
            Assert.Equal(404, exception.Response.StatusCode);

            // TODO GitHubIssue#288 : 204 is expected.
            // Query an Navigation Property
            try
            {
                airline2 = this.TestClientContext.Flights.ByKey(new Dictionary<string, object>() { { "FlightId", flight.FlightId } }).Airline.GetValue();
            }
            catch (DataServiceQueryException e)
            {
                Assert.Equal(404, e.Response.StatusCode);
            }
        }
        public void FilterBuiltInDateFunctions()
        {
            this.TestClientContext.MergeOption = MergeOption.OverwriteChanges;
            DateTime startDate = DateTime.Now.AddYears(1);
            DateTime endDate = startDate.AddHours(5);
            TimeSpan duration = endDate - startDate;
            // Post an entity
            Flight flight = new Flight()
            {
                ConfirmationCode = "MU58496",
                FlightNumber = "MU589",
                StartsAt = startDate,
                EndsAt = endDate,
                // TODO GitHubIssue#47 : SQL issue when duration length greater than 1 day
                // How to describe a timespan equal to or greater than 1 day.
                Duration = duration,
                AirlineId = "MU",
                SeatNumber = "C32",
                FromId = "KSEA",
                ToId = "ZSSS"
            };
            this.TestClientContext.AddToFlights(flight);
            this.TestClientContext.SaveChanges();

            var flightId = flight.FlightId;

            // year(DateTimeOffset) && month(DateTimeOffset)
            var flight1 = this.TestClientContext.Flights
                .Where(f => f.StartsAt.Year == startDate.Year
                    && f.StartsAt.Month == startDate.Month).ToList();
            Assert.True(flight1.Any(f => f.FlightId == flightId));
            Assert.True(flight1.All(f => f.StartsAt.Year == startDate.Year));
            Assert.True(flight1.All(f => f.StartsAt.Month == startDate.Month));

            // day(DateTimeOffset)
            flight1 = this.TestClientContext.Flights.Where(f => f.StartsAt.Day == startDate.Day).ToList();
            Assert.True(flight1.Any(f => f.FlightId == flightId));
            Assert.True(flight1.All(f => f.StartsAt.Day == startDate.Day));

            // hour(DateTimeOffset)
            flight1 = this.TestClientContext.Flights.Where(f => f.StartsAt.Hour == startDate.Hour).ToList();
            Assert.True(flight1.Any(f => f.FlightId == flightId));
            Assert.True(flight1.All(f => f.StartsAt.Hour == startDate.Hour));

            // minute(DateTimeOffset)
            flight1 = this.TestClientContext.Flights.Where(f => f.StartsAt.Minute == startDate.Minute).ToList();
            Assert.True(flight1.Any(f => f.FlightId == flightId));
            Assert.True(flight1.All(f => f.StartsAt.Minute == startDate.Minute));

            // second(DateTimeOffset)
            flight1 = this.TestClientContext.Flights.Where(f => f.StartsAt.Second == startDate.Second).ToList();
            Assert.True(flight1.Any(f => f.FlightId == flightId));
            Assert.True(flight1.All(f => f.StartsAt.Second == startDate.Second));

            // Following built-in functions are not supported now.
            // fractionalseconds 
            // date
            // time
            // totaloffsetminutes
            // now
            // mindatetime
            // maxdatetime
            // totalseconds
        }
        public void BatchRequest()
        {
            this.TestClientContext.MergeOption = Microsoft.OData.Client.MergeOption.OverwriteChanges;
            SaveChangesOptions[] options = new SaveChangesOptions[]
            {
                SaveChangesOptions.BatchWithSingleChangeset,
                SaveChangesOptions.BatchWithIndependentOperations
            };

            Airline airline = new Airline()
            {
                Name = "American Delta",
                AirlineCode = "DL",
                TimeStampValue = new byte[] { 0 }
            };

            // Post an entity
            Flight flight = new Flight()
            {
                ConfirmationCode = "JH58496",
                FlightNumber = "DL589",
                StartsAt = new DateTimeOffset(new DateTime(2014, 2, 10, 15, 00, 0)),
                EndsAt = new DateTimeOffset(new DateTime(2014, 2, 10, 16, 30, 0)),
                AirlineId = "DL",
                SeatNumber = "C32",
                FromId = "KSEA",
                ToId = "ZSSS"
            };

            foreach (var option in options)
            {
                this.TestClientContext.ResetDataSource().Execute();
                this.TestClientContext.AddToAirlines(airline);
                this.TestClientContext.AddToFlights(flight);
                DataServiceResponse response1 = this.TestClientContext.SaveChanges(option);
                if (response1.BatchStatusCode != 200)
                {
                    Assert.NotNull(response1);
                }
                Assert.True(response1.IsBatchResponse);
                foreach (OperationResponse item in response1)
                {
                    Assert.Equal(201, item.StatusCode);
                }
                Assert.Equal(2, response1.Count());

                this.TestClientContext.Detach(airline);
                this.TestClientContext.Detach(flight);

                var request1 = this.TestClientContext.Airlines.Where(al => al.AirlineCode == airline.AirlineCode) as DataServiceQuery<Airline>;
                var request2 = this.TestClientContext.Flights.Where(f => f.FlightId == flight.FlightId) as DataServiceQuery<Flight>;
                var response2 = this.TestClientContext.ExecuteBatch(new DataServiceRequest[] { request1, request2 });
                Assert.NotNull(response2);
                Assert.True(response2.IsBatchResponse);
                var resp2 = response2.ToList();
                Assert.Equal(2, resp2.Count());
                foreach (QueryOperationResponse item in resp2)
                {
                    Assert.Equal(200, item.StatusCode);
                }
                this.TestClientContext.Detach(airline);
                this.TestClientContext.Detach(flight);
            }
        }