Skip to content

Commit 7df5233

Browse files
committed
fix: support for entity resource split
1 parent bcbf8c3 commit 7df5233

File tree

1 file changed

+44
-46
lines changed

1 file changed

+44
-46
lines changed

src/JsonApiDotNetCore/Data/DefaultEntityRepository.cs

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
using JsonApiDotNetCore.Services;
1212
using Microsoft.EntityFrameworkCore;
1313
using Microsoft.Extensions.Logging;
14-
1514
namespace JsonApiDotNetCore.Data
1615
{
1716
/// <inheritdoc />
@@ -30,7 +29,7 @@ public DefaultEntityRepository(
3029
public DefaultEntityRepository(
3130
ILoggerFactory loggerFactory,
3231
IJsonApiContext jsonApiContext,
33-
IDbContextResolver contextResolver,
32+
IDbContextResolver contextResolver,
3433
ResourceDefinition<TEntity> resourceDefinition = null)
3534
: base(loggerFactory, jsonApiContext, contextResolver, resourceDefinition)
3635
{ }
@@ -51,7 +50,6 @@ public class DefaultEntityRepository<TEntity, TId>
5150
private readonly IJsonApiContext _jsonApiContext;
5251
private readonly IGenericProcessorFactory _genericProcessorFactory;
5352
private readonly ResourceDefinition<TEntity> _resourceDefinition;
54-
5553
public DefaultEntityRepository(
5654
IJsonApiContext jsonApiContext,
5755
IDbContextResolver contextResolver,
@@ -102,7 +100,6 @@ public virtual IQueryable<TEntity> Filter(IQueryable<TEntity> entities, FilterQu
102100
return defaultQueryFilter(entities, filterQuery);
103101
}
104102
}
105-
106103
return entities.Filter(_jsonApiContext, filterQuery);
107104
}
108105

@@ -124,7 +121,6 @@ public virtual IQueryable<TEntity> Sort(IQueryable<TEntity> entities, List<SortQ
124121
}
125122
}
126123
}
127-
128124
return entities;
129125
}
130126

@@ -149,22 +145,17 @@ public virtual async Task<TEntity> GetAndIncludeAsync(TId id, string relationshi
149145
public virtual async Task<TEntity> CreateAsync(TEntity entity)
150146
{
151147
AttachRelationships(entity);
152-
foreach (var relationshipEntry in _jsonApiContext.RelationshipsToUpdate)
153-
{
154-
var relationshipValue = relationshipEntry.Value;
155-
if (relationshipEntry.Key is HasManyThroughAttribute throughAttribute)
156-
{
157-
AssignHasManyThrough(entity, throughAttribute, (IList)relationshipValue);
158-
}
159-
}
160-
148+
AssignRelationshipValues(entity);
161149
_dbSet.Add(entity);
162150

163151
await _context.SaveChangesAsync();
164152

165153
return entity;
166154
}
167155

156+
/// <summary>
157+
158+
/// </summary>
168159
protected virtual void AttachRelationships(TEntity entity = null)
169160
{
170161
AttachHasManyAndHasManyThroughPointers(entity);
@@ -232,27 +223,7 @@ public virtual async Task<TEntity> UpdateAsync(TId id, TEntity entity)
232223
if (_jsonApiContext.RelationshipsToUpdate.Any())
233224
{
234225
AttachRelationships(oldEntity);
235-
foreach (var relationshipEntry in _jsonApiContext.RelationshipsToUpdate)
236-
{
237-
var relationshipValue = relationshipEntry.Value;
238-
if (relationshipEntry.Key is HasManyThroughAttribute throughAttribute)
239-
{
240-
// load relations to enforce complete replace
241-
await _context.Entry(oldEntity).Collection(throughAttribute.InternalThroughName).LoadAsync();
242-
AssignHasManyThrough(oldEntity, throughAttribute, (IList)relationshipValue);
243-
} else if (relationshipEntry.Key is HasManyAttribute hasManyAttribute)
244-
{
245-
// load relations to enforce complete replace
246-
await _context.Entry(oldEntity).Collection(hasManyAttribute.InternalRelationshipName).LoadAsync();
247-
// todo: need to load inverse relationship here, see issue #502
248-
hasManyAttribute.SetValue(oldEntity, relationshipValue);
249-
}
250-
else if (relationshipEntry.Key is HasOneAttribute hasOneAttribute)
251-
{
252-
// todo: need to load inverse relationship here, see issue #502
253-
hasOneAttribute.SetValue(oldEntity, relationshipValue);
254-
}
255-
}
226+
AssignRelationshipValues(oldEntity, update: true);
256227
}
257228
await _context.SaveChangesAsync();
258229
return oldEntity;
@@ -273,18 +244,14 @@ public async Task UpdateRelationshipsAsync(object parent, RelationshipAttribute
273244
await genericProcessor.UpdateRelationshipsAsync(parent, relationship, relationshipIds);
274245
}
275246

247+
276248
/// <inheritdoc />
277249
public virtual async Task<bool> DeleteAsync(TId id)
278250
{
279251
var entity = await GetAsync(id);
280-
281-
if (entity == null)
282-
return false;
283-
252+
if (entity == null) return false;
284253
_dbSet.Remove(entity);
285-
286254
await _context.SaveChangesAsync();
287-
288255
return true;
289256
}
290257

@@ -392,14 +359,45 @@ private void AttachHasManyAndHasManyThroughPointers(TEntity entity)
392359

393360
if (pointers == null) continue;
394361
bool alreadyTracked = false;
362+
Type entityType = null;
395363
var newPointerCollection = pointers.Select(pointer =>
396364
{
365+
entityType = pointer.GetType();
397366
var tracked = AttachOrGetTracked(pointer);
398367
if (tracked != null) alreadyTracked = true;
399-
return tracked ?? pointer;
400-
}).Cast(attribute.Type);
368+
return Convert.ChangeType(tracked ?? pointer, entityType);
369+
}).ToList().Cast(entityType);
401370

402-
if (alreadyTracked) relationships[attribute] = (IList)newPointerCollection;
371+
if (alreadyTracked || pointers != relationships[attribute]) relationships[attribute] = (IList)newPointerCollection;
372+
}
373+
}
374+
375+
/// <summary>
376+
/// todo: comments
377+
/// </summary>
378+
protected void AssignRelationshipValues(TEntity oldEntity, bool update = false)
379+
{
380+
foreach (var relationshipEntry in _jsonApiContext.RelationshipsToUpdate)
381+
{
382+
var relationshipValue = relationshipEntry.Value;
383+
if (relationshipEntry.Key is HasManyThroughAttribute throughAttribute)
384+
{
385+
// load relations to enforce complete replace in case of patch
386+
if (update) _context.Entry(oldEntity).Collection(throughAttribute.InternalThroughName).Load();
387+
AssignHasManyThrough(oldEntity, throughAttribute, (IList)relationshipValue);
388+
}
389+
else if (relationshipEntry.Key is HasManyAttribute hasManyAttribute)
390+
{
391+
// load relations to enforce complete replace
392+
if (update) _context.Entry(oldEntity).Collection(hasManyAttribute.InternalRelationshipName).Load();
393+
// todo: need to load inverse relationship here, see issue #502
394+
hasManyAttribute.SetValue(oldEntity, relationshipValue);
395+
}
396+
else if (relationshipEntry.Key is HasOneAttribute hasOneAttribute)
397+
{
398+
// todo: need to load inverse relationship here, see issue #502
399+
if (update) hasOneAttribute.SetValue(oldEntity, relationshipValue);
400+
}
403401
}
404402
}
405403

@@ -409,7 +407,7 @@ private void AttachHasManyAndHasManyThroughPointers(TEntity entity)
409407
/// use the join table (ArticleTags). This methods assigns the relationship value to entity
410408
/// by taking care of that
411409
/// </summary>
412-
protected void AssignHasManyThrough(TEntity entity, HasManyThroughAttribute hasManyThrough, IList relationshipValue)
410+
private void AssignHasManyThrough(TEntity entity, HasManyThroughAttribute hasManyThrough, IList relationshipValue)
413411
{
414412
var pointers = relationshipValue.Cast<IIdentifiable>();
415413
var throughRelationshipCollection = Activator.CreateInstance(hasManyThrough.ThroughProperty.PropertyType) as IList;
@@ -438,7 +436,7 @@ private void AttachHasOnePointers(TEntity entity)
438436
var pointer = GetRelationshipPointer(entity, attribute) ?? relationships[attribute];
439437
if (pointer == null) return;
440438
var tracked = AttachOrGetTracked(pointer);
441-
if (tracked != null) relationships[attribute] = tracked;
439+
if (tracked != null || pointer != relationships[attribute]) relationships[attribute] = tracked ?? pointer;
442440
}
443441
}
444442

0 commit comments

Comments
 (0)