Skip to content

Commit 0bcffe5

Browse files
authored
Merge pull request #333 from json-api-dotnet/fix/#322
fix(relationship pointers): key pointers by RelationshipAttribute
2 parents d67a894 + 513ec19 commit 0bcffe5

File tree

5 files changed

+88
-19
lines changed

5 files changed

+88
-19
lines changed

src/JsonApiDotNetCore/JsonApiDotNetCore.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<VersionPrefix>2.3.4</VersionPrefix>
3+
<VersionPrefix>2.3.5</VersionPrefix>
44
<TargetFrameworks>$(NetStandardVersion)</TargetFrameworks>
55
<AssemblyName>JsonApiDotNetCore</AssemblyName>
66
<PackageId>JsonApiDotNetCore</PackageId>

src/JsonApiDotNetCore/Request/HasManyRelationshipPointers.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
using System;
21
using System.Collections;
32
using System.Collections.Generic;
3+
using JsonApiDotNetCore.Models;
44

55
namespace JsonApiDotNetCore.Request
66
{
@@ -32,18 +32,18 @@ namespace JsonApiDotNetCore.Request
3232
/// </summary>
3333
public class HasManyRelationshipPointers
3434
{
35-
private Dictionary<Type, IList> _hasManyRelationships = new Dictionary<Type, IList>();
35+
private Dictionary<RelationshipAttribute, IList> _hasManyRelationships = new Dictionary<RelationshipAttribute, IList>();
3636

3737
/// <summary>
3838
/// Add the relationship to the list of relationships that should be
3939
/// set in the repository layer.
4040
/// </summary>
41-
public void Add(Type dependentType, IList entities)
42-
=> _hasManyRelationships[dependentType] = entities;
41+
public void Add(RelationshipAttribute relationship, IList entities)
42+
=> _hasManyRelationships[relationship] = entities;
4343

4444
/// <summary>
4545
/// Get all the models that should be associated
4646
/// </summary>
47-
public Dictionary<Type, IList> Get() => _hasManyRelationships;
47+
public Dictionary<RelationshipAttribute, IList> Get() => _hasManyRelationships;
4848
}
4949
}

src/JsonApiDotNetCore/Request/HasOneRelationshipPointers.cs

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using JsonApiDotNetCore.Models;
2-
using System;
32
using System.Collections.Generic;
43

54
namespace JsonApiDotNetCore.Request
@@ -29,18 +28,18 @@ namespace JsonApiDotNetCore.Request
2928
/// </summary>
3029
public class HasOneRelationshipPointers
3130
{
32-
private Dictionary<Type, IIdentifiable> _hasOneRelationships = new Dictionary<Type, IIdentifiable>();
31+
private Dictionary<RelationshipAttribute, IIdentifiable> _hasOneRelationships = new Dictionary<RelationshipAttribute, IIdentifiable>();
3332

3433
/// <summary>
3534
/// Add the relationship to the list of relationships that should be
3635
/// set in the repository layer.
3736
/// </summary>
38-
public void Add(Type dependentType, IIdentifiable entity)
39-
=> _hasOneRelationships[dependentType] = entity;
37+
public void Add(RelationshipAttribute relationship, IIdentifiable entity)
38+
=> _hasOneRelationships[relationship] = entity;
4039

4140
/// <summary>
4241
/// Get all the models that should be associated
4342
/// </summary>
44-
public Dictionary<Type, IIdentifiable> Get() => _hasOneRelationships;
43+
public Dictionary<RelationshipAttribute, IIdentifiable> Get() => _hasOneRelationships;
4544
}
4645
}

src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ public object DocumentToObject(DocumentData data, List<DocumentData> included =
124124
+ "If you have manually registered the resource, check that the call to AddResource correctly sets the public name."); ;
125125

126126
var entity = Activator.CreateInstance(contextEntity.EntityType);
127-
127+
128128
entity = SetEntityAttributes(entity, contextEntity, data.Attributes);
129129
entity = SetRelationships(entity, contextEntity, data.Relationships, included);
130130

@@ -141,7 +141,7 @@ private object SetEntityAttributes(
141141
{
142142
if (attributeValues == null || attributeValues.Count == 0)
143143
return entity;
144-
144+
145145
foreach (var attr in contextEntity.Attributes)
146146
{
147147
if (attributeValues.TryGetValue(attr.PublicAttributeName, out object newValue))
@@ -174,7 +174,7 @@ private object DeserializeComplexType(JContainer obj, Type targetType)
174174
private object SetRelationships(
175175
object entity,
176176
ContextEntity contextEntity,
177-
Dictionary<string, RelationshipData> relationships,
177+
Dictionary<string, RelationshipData> relationships,
178178
List<DocumentData> included = null)
179179
{
180180
if (relationships == null || relationships.Count == 0)
@@ -203,7 +203,7 @@ private object SetHasOneRelationship(object entity,
203203

204204
if (relationships.TryGetValue(relationshipName, out RelationshipData relationshipData) == false)
205205
return entity;
206-
206+
207207
var relationshipAttr = _jsonApiContext.RequestEntity.Relationships
208208
.SingleOrDefault(r => r.PublicRelationshipName == relationshipName);
209209

@@ -234,7 +234,7 @@ private object SetHasOneRelationship(object entity,
234234
foreignKeyProperty.SetValue(entity, convertedValue);
235235

236236

237-
if(rio != null
237+
if (rio != null
238238
// if the resource identifier is null, there should be no reason to instantiate an instance
239239
&& rio.Id != null)
240240
{
@@ -247,7 +247,7 @@ private object SetHasOneRelationship(object entity,
247247
// we need to store the fact that this relationship was included in the payload
248248
// for EF, the repository will use these pointers to make ensure we don't try to
249249
// create resources if they already exist, we just need to create the relationship
250-
_jsonApiContext.HasOneRelationshipPointers.Add(attr.Type, includedRelationshipObject);
250+
_jsonApiContext.HasOneRelationshipPointers.Add(attr, includedRelationshipObject);
251251
}
252252

253253
return entity;
@@ -278,7 +278,7 @@ private object SetHasManyRelationship(object entity,
278278

279279
attr.SetValue(entity, convertedCollection);
280280

281-
_jsonApiContext.HasManyRelationshipPointers.Add(attr.Type, convertedCollection);
281+
_jsonApiContext.HasManyRelationshipPointers.Add(attr, convertedCollection);
282282
}
283283

284284
return entity;
@@ -301,7 +301,7 @@ private IIdentifiable GetIncludedRelationship(ResourceIdentifierObject relatedRe
301301
var contextEntity = _jsonApiContext.ContextGraph.GetContextEntity(relationshipAttr.Type);
302302
if (contextEntity == null)
303303
throw new JsonApiException(400, $"Included type '{relationshipAttr.Type}' is not a registered json:api resource.");
304-
304+
305305
SetEntityAttributes(relatedInstance, contextEntity, includedResource.Attributes);
306306

307307
return relatedInstance;

test/JsonApiDotNetCoreExampleTests/Acceptance/TodoItemsControllerTests.cs

+70
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
using System.Net.Http.Headers;
66
using System.Threading.Tasks;
77
using Bogus;
8+
using JsonApiDotNetCore.Models;
89
using JsonApiDotNetCore.Serialization;
910
using JsonApiDotNetCore.Services;
1011
using JsonApiDotNetCoreExample.Data;
1112
using JsonApiDotNetCoreExample.Models;
13+
using Microsoft.EntityFrameworkCore;
1214
using Newtonsoft.Json;
1315
using Xunit;
1416
using Person = JsonApiDotNetCoreExample.Models.Person;
@@ -304,6 +306,74 @@ public async Task Can_Post_TodoItem()
304306
Assert.Null(deserializedBody.AchievedDate);
305307
}
306308

309+
310+
[Fact]
311+
public async Task Can_Post_TodoItem_With_Different_Owner_And_Assignee()
312+
{
313+
// Arrange
314+
var person1 = new Person();
315+
var person2 = new Person();
316+
_context.People.Add(person1);
317+
_context.People.Add(person2);
318+
_context.SaveChanges();
319+
320+
var todoItem = _todoItemFaker.Generate();
321+
var content = new
322+
{
323+
data = new
324+
{
325+
type = "todo-items",
326+
attributes = new Dictionary<string, object>()
327+
{
328+
{ "description", todoItem.Description },
329+
{ "ordinal", todoItem.Ordinal },
330+
{ "created-date", todoItem.CreatedDate }
331+
},
332+
relationships = new
333+
{
334+
owner = new
335+
{
336+
data = new
337+
{
338+
type = "people",
339+
id = person1.Id.ToString()
340+
}
341+
},
342+
assignee = new
343+
{
344+
data = new
345+
{
346+
type = "people",
347+
id = person2.Id.ToString()
348+
}
349+
}
350+
}
351+
}
352+
};
353+
354+
var httpMethod = new HttpMethod("POST");
355+
var route = $"/api/v1/todo-items";
356+
357+
var request = new HttpRequestMessage(httpMethod, route);
358+
request.Content = new StringContent(JsonConvert.SerializeObject(content));
359+
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json");
360+
361+
// Act
362+
var response = await _fixture.Client.SendAsync(request);
363+
364+
// Assert -- response
365+
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
366+
var body = await response.Content.ReadAsStringAsync();
367+
var document = JsonConvert.DeserializeObject<Document>(body);
368+
var resultId = int.Parse(document.Data.Id);
369+
370+
// Assert -- database
371+
var todoItemResult = await _context.TodoItems.SingleAsync(t => t.Id == resultId);
372+
373+
Assert.Equal(person1.Id, todoItemResult.OwnerId);
374+
Assert.Equal(person2.Id, todoItemResult.AssigneeId);
375+
}
376+
307377
[Fact]
308378
public async Task Can_Patch_TodoItem()
309379
{

0 commit comments

Comments
 (0)