diff --git a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj index a75fd0d23a..d222f49376 100755 --- a/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj +++ b/src/JsonApiDotNetCore/JsonApiDotNetCore.csproj @@ -1,6 +1,6 @@ - 2.3.4 + 2.3.5 $(NetStandardVersion) JsonApiDotNetCore JsonApiDotNetCore diff --git a/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs b/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs index 721274e3d6..04056e4af8 100644 --- a/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs +++ b/src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs @@ -1,6 +1,6 @@ -using System; using System.Collections; using System.Collections.Generic; +using JsonApiDotNetCore.Models; namespace JsonApiDotNetCore.Request { @@ -32,18 +32,18 @@ namespace JsonApiDotNetCore.Request /// public class HasManyRelationshipPointers { - private Dictionary _hasManyRelationships = new Dictionary(); + private Dictionary _hasManyRelationships = new Dictionary(); /// /// Add the relationship to the list of relationships that should be /// set in the repository layer. /// - public void Add(Type dependentType, IList entities) - => _hasManyRelationships[dependentType] = entities; + public void Add(RelationshipAttribute relationship, IList entities) + => _hasManyRelationships[relationship] = entities; /// /// Get all the models that should be associated /// - public Dictionary Get() => _hasManyRelationships; + public Dictionary Get() => _hasManyRelationships; } } diff --git a/src/JsonApiDotNetCore/Request/HasOneRelationshipPointers.cs b/src/JsonApiDotNetCore/Request/HasOneRelationshipPointers.cs index 9e0bdd0e15..753aa35e98 100644 --- a/src/JsonApiDotNetCore/Request/HasOneRelationshipPointers.cs +++ b/src/JsonApiDotNetCore/Request/HasOneRelationshipPointers.cs @@ -1,5 +1,4 @@ using JsonApiDotNetCore.Models; -using System; using System.Collections.Generic; namespace JsonApiDotNetCore.Request @@ -29,18 +28,18 @@ namespace JsonApiDotNetCore.Request /// public class HasOneRelationshipPointers { - private Dictionary _hasOneRelationships = new Dictionary(); + private Dictionary _hasOneRelationships = new Dictionary(); /// /// Add the relationship to the list of relationships that should be /// set in the repository layer. /// - public void Add(Type dependentType, IIdentifiable entity) - => _hasOneRelationships[dependentType] = entity; + public void Add(RelationshipAttribute relationship, IIdentifiable entity) + => _hasOneRelationships[relationship] = entity; /// /// Get all the models that should be associated /// - public Dictionary Get() => _hasOneRelationships; + public Dictionary Get() => _hasOneRelationships; } } diff --git a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs index 8b5a94f201..5ad0a2b63d 100644 --- a/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs +++ b/src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs @@ -124,7 +124,7 @@ public object DocumentToObject(DocumentData data, List included = + "If you have manually registered the resource, check that the call to AddResource correctly sets the public name."); ; var entity = Activator.CreateInstance(contextEntity.EntityType); - + entity = SetEntityAttributes(entity, contextEntity, data.Attributes); entity = SetRelationships(entity, contextEntity, data.Relationships, included); @@ -141,7 +141,7 @@ private object SetEntityAttributes( { if (attributeValues == null || attributeValues.Count == 0) return entity; - + foreach (var attr in contextEntity.Attributes) { if (attributeValues.TryGetValue(attr.PublicAttributeName, out object newValue)) @@ -174,7 +174,7 @@ private object DeserializeComplexType(JContainer obj, Type targetType) private object SetRelationships( object entity, ContextEntity contextEntity, - Dictionary relationships, + Dictionary relationships, List included = null) { if (relationships == null || relationships.Count == 0) @@ -203,7 +203,7 @@ private object SetHasOneRelationship(object entity, if (relationships.TryGetValue(relationshipName, out RelationshipData relationshipData) == false) return entity; - + var relationshipAttr = _jsonApiContext.RequestEntity.Relationships .SingleOrDefault(r => r.PublicRelationshipName == relationshipName); @@ -234,7 +234,7 @@ private object SetHasOneRelationship(object entity, foreignKeyProperty.SetValue(entity, convertedValue); - if(rio != null + if (rio != null // if the resource identifier is null, there should be no reason to instantiate an instance && rio.Id != null) { @@ -247,7 +247,7 @@ private object SetHasOneRelationship(object entity, // we need to store the fact that this relationship was included in the payload // for EF, the repository will use these pointers to make ensure we don't try to // create resources if they already exist, we just need to create the relationship - _jsonApiContext.HasOneRelationshipPointers.Add(attr.Type, includedRelationshipObject); + _jsonApiContext.HasOneRelationshipPointers.Add(attr, includedRelationshipObject); } return entity; @@ -278,7 +278,7 @@ private object SetHasManyRelationship(object entity, attr.SetValue(entity, convertedCollection); - _jsonApiContext.HasManyRelationshipPointers.Add(attr.Type, convertedCollection); + _jsonApiContext.HasManyRelationshipPointers.Add(attr, convertedCollection); } return entity; @@ -301,7 +301,7 @@ private IIdentifiable GetIncludedRelationship(ResourceIdentifierObject relatedRe var contextEntity = _jsonApiContext.ContextGraph.GetContextEntity(relationshipAttr.Type); if (contextEntity == null) throw new JsonApiException(400, $"Included type '{relationshipAttr.Type}' is not a registered json:api resource."); - + SetEntityAttributes(relatedInstance, contextEntity, includedResource.Attributes); return relatedInstance; diff --git a/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs b/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs index cf1ea6de96..0600fb402b 100644 --- a/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs +++ b/test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs @@ -5,10 +5,12 @@ using System.Net.Http.Headers; using System.Threading.Tasks; using Bogus; +using JsonApiDotNetCore.Models; using JsonApiDotNetCore.Serialization; using JsonApiDotNetCore.Services; using JsonApiDotNetCoreExample.Data; using JsonApiDotNetCoreExample.Models; +using Microsoft.EntityFrameworkCore; using Newtonsoft.Json; using Xunit; using Person = JsonApiDotNetCoreExample.Models.Person; @@ -304,6 +306,74 @@ public async Task Can_Post_TodoItem() Assert.Null(deserializedBody.AchievedDate); } + + [Fact] + public async Task Can_Post_TodoItem_With_Different_Owner_And_Assignee() + { + // Arrange + var person1 = new Person(); + var person2 = new Person(); + _context.People.Add(person1); + _context.People.Add(person2); + _context.SaveChanges(); + + var todoItem = _todoItemFaker.Generate(); + var content = new + { + data = new + { + type = "todo-items", + attributes = new Dictionary() + { + { "description", todoItem.Description }, + { "ordinal", todoItem.Ordinal }, + { "created-date", todoItem.CreatedDate } + }, + relationships = new + { + owner = new + { + data = new + { + type = "people", + id = person1.Id.ToString() + } + }, + assignee = new + { + data = new + { + type = "people", + id = person2.Id.ToString() + } + } + } + } + }; + + var httpMethod = new HttpMethod("POST"); + var route = $"/api/v1/todo-items"; + + var request = new HttpRequestMessage(httpMethod, route); + request.Content = new StringContent(JsonConvert.SerializeObject(content)); + request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); + + // Act + var response = await _fixture.Client.SendAsync(request); + + // Assert -- response + Assert.Equal(HttpStatusCode.Created, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + var document = JsonConvert.DeserializeObject(body); + var resultId = int.Parse(document.Data.Id); + + // Assert -- database + var todoItemResult = await _context.TodoItems.SingleAsync(t => t.Id == resultId); + + Assert.Equal(person1.Id, todoItemResult.OwnerId); + Assert.Equal(person2.Id, todoItemResult.AssigneeId); + } + [Fact] public async Task Can_Patch_TodoItem() {