diff --git a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs index 2d2c978179..1287f35a05 100644 --- a/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs +++ b/src/JsonApiDotNetCore/Builders/DocumentBuilder.cs @@ -218,6 +218,8 @@ private List IncludeRelationshipChain( throw new JsonApiException(400, $"{parentEntity.EntityName} does not contain relationship {requestedRelationship}"); var navigationEntity = _jsonApiContext.ResourceGraph.GetRelationshipValue(parentResource, relationship); + if(navigationEntity == null) + return included; if (navigationEntity is IEnumerable hasManyNavigationEntity) { foreach (IIdentifiable includedEntity in hasManyNavigationEntity) diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs index cfe842616b..18750a6b00 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/Spec/DocumentTests/Included.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using System.Net; using System.Net.Http; @@ -358,5 +359,56 @@ public async Task Request_ToIncludeRelationshipMarkedCanIncludeFalse_Returns_400 // assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } + + [Fact] + public async Task Can_Ignore_Null_Parent_In_Nested_Include() + { + // arrange + var todoItem = _todoItemFaker.Generate(); + todoItem.Owner = _personFaker.Generate(); + todoItem.CreatedDate = DateTime.Now; + _context.TodoItems.Add(todoItem); + _context.SaveChanges(); + + var todoItemWithNullOwner = _todoItemFaker.Generate(); + todoItemWithNullOwner.Owner = null; + todoItemWithNullOwner.CreatedDate = DateTime.Now; + _context.TodoItems.Add(todoItemWithNullOwner); + _context.SaveChanges(); + + var builder = new WebHostBuilder() + .UseStartup(); + + var httpMethod = new HttpMethod("GET"); + + var route = $"/api/v1/todo-items?sort=-created-date&page[size]=2&include=owner.role"; // last two todo-items + + var server = new TestServer(builder); + var client = server.CreateClient(); + var request = new HttpRequestMessage(httpMethod, route); + + // act + var response = await client.SendAsync(request); + var responseString = await response.Content.ReadAsStringAsync(); + var documents = JsonConvert.DeserializeObject(responseString); + + // assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + Assert.Single(documents.Included); + + var ownerValueNull = documents.Data + .First(i => i.Id == todoItemWithNullOwner.StringId) + .Relationships.First(i => i.Key == "owner") + .Value.SingleData; + + Assert.Null(ownerValueNull); + + var ownerValue = documents.Data + .First(i => i.Id == todoItem.StringId) + .Relationships.First(i => i.Key == "owner") + .Value.SingleData; + + Assert.NotNull(ownerValue); + } } }