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); } }