Skip to content

Commit 1062ea9

Browse files
committed
set new HasManyRelationships with EntityState.Unchanged
1 parent 7288de2 commit 1062ea9

File tree

7 files changed

+78
-25
lines changed

7 files changed

+78
-25
lines changed

src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,29 @@ public virtual async Task<TEntity> GetAndIncludeAsync(TId id, string relationshi
8585
public virtual async Task<TEntity> CreateAsync(TEntity entity)
8686
{
8787
_dbSet.Add(entity);
88+
89+
DetachHasManyPointers();
90+
8891
await _context.SaveChangesAsync();
8992
return entity;
9093
}
9194

95+
/// <summary>
96+
/// This is used to allow creation of HasMany relationships when the
97+
/// dependent side of the relationship already exists.
98+
/// </summary>
99+
private void DetachHasManyPointers()
100+
{
101+
var relationships = _jsonApiContext.HasManyRelationshipPointers.Get();
102+
foreach(var relationship in relationships)
103+
{
104+
foreach(var pointer in relationship.Value)
105+
{
106+
_context.Entry(pointer).State = EntityState.Unchanged;
107+
}
108+
}
109+
}
110+
92111
public virtual async Task<TEntity> UpdateAsync(TId id, TEntity entity)
93112
{
94113
var oldEntity = await GetAsync(id);

src/JsonApiDotNetCore/Data/IEntityRepository.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
using System.Collections.Generic;
2-
using System.Linq;
3-
using System.Threading.Tasks;
4-
using JsonApiDotNetCore.Internal.Query;
51
using JsonApiDotNetCore.Models;
62

73
namespace JsonApiDotNetCore.Data
Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,12 @@
1-
using Microsoft.EntityFrameworkCore;
21
using System;
2+
using Microsoft.EntityFrameworkCore;
33

44
namespace JsonApiDotNetCore.Extensions
55
{
66
public static class DbContextExtensions
77
{
8-
public static DbSet<T> GetDbSet<T>(this DbContext context) where T : class
9-
{
10-
var contextProperties = context.GetType().GetProperties();
11-
foreach(var property in contextProperties)
12-
{
13-
if (property.PropertyType == typeof(DbSet<T>))
14-
return (DbSet<T>)property.GetValue(context);
15-
}
16-
17-
throw new ArgumentException($"DbSet of type {typeof(T).FullName} not found on the DbContext", nameof(T));
18-
}
8+
[Obsolete("This is no longer required since the introduction of context.Set<T>", error: false)]
9+
public static DbSet<T> GetDbSet<T>(this DbContext context) where T : class
10+
=> context.Set<T>();
1911
}
2012
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
5+
namespace JsonApiDotNetCore.Request
6+
{
7+
/// <summary>
8+
/// Stores information to set relationships for the request resource.
9+
/// These relationships must already exist and should not be re-created.
10+
///
11+
/// The expected use case is POST-ing or PATCH-ing
12+
/// an entity with HasMany relaitonships:
13+
/// <code>
14+
/// {
15+
/// "data": {
16+
/// "type": "photos",
17+
/// "attributes": {
18+
/// "title": "Ember Hamster",
19+
/// "src": "http://example.com/images/productivity.png"
20+
/// },
21+
/// "relationships": {
22+
/// "tags": {
23+
/// "data": [
24+
/// { "type": "tags", "id": "2" },
25+
/// { "type": "tags", "id": "3" }
26+
/// ]
27+
/// }
28+
/// }
29+
/// }
30+
/// }
31+
/// </code>
32+
/// </summary>
33+
public class HasManyRelationshipPointers
34+
{
35+
private Dictionary<Type, IList> _hasManyRelationships = new Dictionary<Type, IList>();
36+
37+
/// <summary>
38+
/// Add the relationship to the list of relationships that should be
39+
/// set in the repository layer.
40+
/// </summary>
41+
public void Add(Type dependentType, IList entities)
42+
=> _hasManyRelationships[dependentType] = entities;
43+
44+
/// <summary>
45+
/// Get all the models that should be associated
46+
/// </summary>
47+
public Dictionary<Type, IList> Get() => _hasManyRelationships;
48+
}
49+
}

src/JsonApiDotNetCore/Serialization/JsonApiDeSerializer.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,6 @@ private object SetHasManyRelationship(object entity,
232232
ContextEntity contextEntity,
233233
Dictionary<string, RelationshipData> relationships)
234234
{
235-
// TODO: is this necessary? if not, remove
236-
// var entityProperty = entityProperties.FirstOrDefault(p => p.Name == attr.InternalRelationshipName);
237-
238-
// if (entityProperty == null)
239-
// throw new JsonApiException(400, $"{contextEntity.EntityType.Name} does not contain a relationsip named '{attr.InternalRelationshipName}'");
240-
241235
var relationshipName = attr.PublicRelationshipName;
242236

243237
if (relationships.TryGetValue(relationshipName, out RelationshipData relationshipData))
@@ -255,9 +249,9 @@ private object SetHasManyRelationship(object entity,
255249

256250
var convertedCollection = TypeHelper.ConvertCollection(relationshipShells, attr.Type);
257251

258-
// var convertedCollection = TypeHelper.ConvertCollection(relationshipShells, attr.Type);
259-
260252
attr.SetValue(entity, convertedCollection);
253+
254+
_jsonApiContext.HasManyRelationshipPointers.Add(attr.Type, convertedCollection);
261255
}
262256

263257
return entity;

src/JsonApiDotNetCore/Services/IJsonApiContext.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using JsonApiDotNetCore.Internal.Generics;
77
using JsonApiDotNetCore.Internal.Query;
88
using JsonApiDotNetCore.Models;
9+
using JsonApiDotNetCore.Request;
910

1011
namespace JsonApiDotNetCore.Services
1112
{
@@ -28,6 +29,7 @@ public interface IJsonApiContext
2829
Type ControllerType { get; set; }
2930
Dictionary<string, object> DocumentMeta { get; set; }
3031
bool IsBulkOperationRequest { get; set; }
32+
HasManyRelationshipPointers HasManyRelationshipPointers { get; }
3133

3234
TAttribute GetControllerAttribute<TAttribute>() where TAttribute : Attribute;
3335
}

src/JsonApiDotNetCore/Services/JsonApiContext.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Linq;
43
using JsonApiDotNetCore.Builders;
54
using JsonApiDotNetCore.Configuration;
65
using JsonApiDotNetCore.Internal;
76
using JsonApiDotNetCore.Internal.Generics;
87
using JsonApiDotNetCore.Internal.Query;
98
using JsonApiDotNetCore.Models;
9+
using JsonApiDotNetCore.Request;
1010
using Microsoft.AspNetCore.Http;
1111

1212
namespace JsonApiDotNetCore.Services
@@ -52,6 +52,7 @@ public JsonApiContext(
5252
public Type ControllerType { get; set; }
5353
public Dictionary<string, object> DocumentMeta { get; set; }
5454
public bool IsBulkOperationRequest { get; set; }
55+
public HasManyRelationshipPointers HasManyRelationshipPointers { get; } = new HasManyRelationshipPointers();
5556

5657
public IJsonApiContext ApplyContext<T>(object controller)
5758
{

0 commit comments

Comments
 (0)