Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions MockData/ActionV4Tests.PatchMovieDetails.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"Content":"{\"@odata.type\":\"#WebApiOData.V4.Samples.Models.MovieDetails\",\"Synopsis\":\"Foo!\"}","ContentHeaders":[{"Key":"Content-Type","Value":["application\/json"]},{"Key":"Content-Length","Value":["48"]}],"Method":"PATCH","RequestHeaders":[{"Key":"Accept","Value":["application\/json","application\/xml","application\/text"]},{"Key":"Prefer","Value":["return=representation"]}],"RequestUri":"http:\/\/localhost\/actions\/Movies\/1/Details"}
1 change: 1 addition & 0 deletions MockData/ActionV4Tests.PatchMovieDetails.2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"Content":"{\"@odata.context\":\"http://localhost/actions/$metadata#Movies(1)/Details\",\"value\":[{\"Synopsis\":\"Foo!\"}]}","ContentHeaders":[{"Key":"Content-Type","Value":["application\/json; odata.metadata=minimal"]},{"Key":"Content-Length","Value":["148"]}],"RequestUri":"http:\/\/localhost\/actions\/Movies\/1/Details","ResponseHeaders":[{"Key":"OData-Version","Value":["4.0"]}],"StatusCode":200}
2 changes: 1 addition & 1 deletion src/Simple.OData.Client.Core/Adapter/RequestWriterBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public async Task<ODataRequest> CreateUpdateRequestAsync(

var hasPropertiesToUpdate = entryDetails.Properties.Count > 0;
var usePatch = _session.Settings.PreferredUpdateMethod == ODataUpdateMethod.Patch || !hasPropertiesToUpdate;
if (HasUpdatedKeyProperties(collection, entryKey, entryData))
if (entryKey != null && HasUpdatedKeyProperties(collection, entryKey, entryData))
{
usePatch = false;
}
Expand Down
2 changes: 0 additions & 2 deletions src/Simple.OData.Client.Core/Fluent/RequestBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ public async Task<ODataRequest> UpdateRequestAsync(
bool resultRequired,
CancellationToken cancellationToken)
{
AssertHasKey(_command);

await _session
.ResolveAdapterAsync(cancellationToken)
.ConfigureAwait(false);
Expand Down
12 changes: 12 additions & 0 deletions src/WebApiOData.V4.Samples.Tests/ActionV4Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,16 @@ public async Task CreateMovie_batch()

Assert.True(result.ID > 0);
}

[Fact]
public async Task PatchMovieDetails()
{
var settings = CreateDefaultSettings().WithHttpMock();
var client = new ODataClient(settings);
MovieDetails updated = await client.For<Movie>().Key(1).NavigateTo(m => m.Details!).Set(new
{
Synopsis = "Foo!"
}).UpdateEntryAsync().ConfigureAwait(false);
Assert.Equal("Foo!", updated.Synopsis);
}
}
4 changes: 4 additions & 0 deletions src/WebApiOData.V4.Samples.Tests/Resources/Metadata.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
<Property Name="Title" Type="Edm.String" />
<Property Name="Year" Type="Edm.Int32" Nullable="false" />
<Property Name="DueDate" Type="Edm.DateTimeOffset" />
<NavigationProperty Name="Details" Type="WebApiOData.V4.Samples.Models.MovieDetails" />
</EntityType>
<EntityType Name="MovieDetails">
<Property Name="Synopsis" Type="Edm.String" />
</EntityType>
<EntityType Name="Product">
<Key>
Expand Down
22 changes: 22 additions & 0 deletions src/WebApiOData.V4.Samples/Controllers/MoviesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,28 @@ public IHttpActionResult Get()
return Ok(_db.Movies);
}

public IHttpActionResult GetMovieDetails(int key)
{
var movie = _db.Movies.FirstOrDefault(m => m.ID == key);
if (movie?.Details is not null)
{
return Ok(movie.Details);
}
return NotFound();
}

[HttpPatch]
public IHttpActionResult PatchToMovieDetails(int key, Delta<MovieDetails> delta)
{
var movie = _db.Movies.FirstOrDefault(m => m.ID == key);
if (movie?.Details is not null)
{
delta?.Patch(movie.Details);
return Ok(movie.Details);
}
return NotFound();
}

[HttpPost]
public IHttpActionResult CheckOut(int key)
{
Expand Down
7 changes: 7 additions & 0 deletions src/WebApiOData.V4.Samples/Models/Movie.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,11 @@ public class Movie
public DateTimeOffset? DueDate { get; set; }

public bool IsCheckedOut => DueDate.HasValue;

public MovieDetails? Details { get; set; }
}

public class MovieDetails
{
public string Synopsis { get; set; } = string.Empty;
}
2 changes: 1 addition & 1 deletion src/WebApiOData.V4.Samples/Models/MoviesContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public class MoviesContext
{
public List<Movie> Movies { get; set; } = new List<Movie>()
{
new Movie() { ID=1, Title = "Maximum Payback", Year = 1990 },
new Movie() { ID=1, Title = "Maximum Payback", Year = 1990, Details = new() { Synopsis = "..." } },
new Movie() { ID=2, Title = "Inferno of Retribution", Year = 2005 },
new Movie() { ID=3, Title = "Fatal Vengeance 2", Year = 2012 },
new Movie() { ID=4, Title = "Sudden Danger", Year = 2012 },
Expand Down
2 changes: 2 additions & 0 deletions src/WebApiOData.V4.Samples/Startups/ActionStartup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ private static IEdmModel GetEdmModel(HttpConfiguration config)
var modelBuilder = new ODataConventionModelBuilder(config);
_ = modelBuilder.EntitySet<Movie>("Movies");

modelBuilder.EntityType<Movie>().HasOptional(m => m.Details!).Contained();

// Now add actions.

// CheckOut
Expand Down