1111using JsonApiDotNetCore . Services ;
1212using Microsoft . EntityFrameworkCore ;
1313using Microsoft . Extensions . Logging ;
14-
1514namespace 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