@@ -82,6 +82,7 @@ public DefaultEntityRepository(
8282 public virtual IQueryable < TEntity > Get ( )
8383 => _dbSet ;
8484
85+ /// <inheritdoc />
8586 public virtual IQueryable < TEntity > Select ( IQueryable < TEntity > entities , List < string > fields )
8687 {
8788 if ( fields ? . Count > 0 )
@@ -228,16 +229,16 @@ private void AttachHasMany(TEntity entity, HasManyAttribute relationship, IList
228229 var relatedList = ( IList ) entity . GetType ( ) . GetProperty ( relationship . EntityPropertyName ) ? . GetValue ( entity ) ;
229230 foreach ( var related in relatedList )
230231 {
231- if ( _context . EntityIsTracked ( related as IIdentifiable ) == false )
232+ if ( _context . EntityIsTracked ( ( IIdentifiable ) related ) == false )
232233 _context . Entry ( related ) . State = EntityState . Unchanged ;
233234 }
234235 }
235236 else
236237 {
237238 foreach ( var pointer in pointers )
238239 {
239- if ( _context . EntityIsTracked ( pointer as IIdentifiable ) == false )
240- _context . Entry ( pointer ) . State = EntityState . Unchanged ;
240+ if ( _context . EntityIsTracked ( ( IIdentifiable ) pointer ) == false )
241+ _context . Entry ( pointer ) . State = EntityState . Unchanged ;
241242 }
242243 }
243244 }
@@ -266,31 +267,49 @@ private void AttachHasManyThrough(TEntity entity, HasManyThroughAttribute hasMan
266267
267268 /// <summary>
268269 /// This is used to allow creation of HasOne relationships when the
269- /// independent side of the relationship already exists.
270270 /// </summary>
271271 private void AttachHasOnePointers ( TEntity entity )
272272 {
273- var relationships = _jsonApiContext . HasOneRelationshipPointers . Get ( ) ;
273+ var relationships = _jsonApiContext
274+ . HasOneRelationshipPointers
275+ . Get ( ) ;
276+
274277 foreach ( var relationship in relationships )
275278 {
276- if ( relationship . Key . GetType ( ) != typeof ( HasOneAttribute ) )
277- continue ;
279+ var pointer = GetValueFromRelationship ( entity , relationship ) ;
280+ if ( pointer == null ) return ;
281+ var trackedEntity = _context . GetTrackedEntity ( pointer ) ;
278282
279- var hasOne = ( HasOneAttribute ) relationship . Key ;
280- if ( hasOne . EntityPropertyName ! = null )
283+ // useful article: https://stackoverflow.com/questions/30987806/dbset-attachentity-vs-dbcontext-entryentity-state-entitystate-modified
284+ if ( trackedEntity = = null )
281285 {
282- var relatedEntity = entity . GetType ( ) . GetProperty ( hasOne . EntityPropertyName ) ? . GetValue ( entity ) ;
283- if ( relatedEntity != null && _context . Entry ( relatedEntity ) . State == EntityState . Detached && _context . EntityIsTracked ( ( IIdentifiable ) relatedEntity ) == false )
284- _context . Entry ( relatedEntity ) . State = EntityState . Unchanged ;
285- }
286- else
286+ /// the relationship pointer is new to EF Core, but we are sure
287+ /// it exists in the database (json:api spec), so we attach it.
288+ _context . Entry ( pointer ) . State = EntityState . Unchanged ;
289+ } else
287290 {
288- if ( _context . Entry ( relationship . Value ) . State == EntityState . Detached && _context . EntityIsTracked ( relationship . Value ) == false )
289- _context . Entry ( relationship . Value ) . State = EntityState . Unchanged ;
291+ /// there already was an instance of this type and ID tracked
292+ /// by EF Core. Reattaching is not allowed, and from now on we
293+ /// will use the already attached one instead. (This entry might
294+ /// contain updated fields as a result of Business logic.
295+ relationships [ relationship . Key ] = trackedEntity ;
290296 }
297+
291298 }
292299 }
293300
301+ IIdentifiable GetValueFromRelationship ( TEntity principalEntity , KeyValuePair < RelationshipAttribute , IIdentifiable > relationship )
302+ {
303+ HasOneAttribute hasOne = ( HasOneAttribute ) relationship . Key ;
304+ if ( hasOne . EntityPropertyName != null )
305+ {
306+ var relatedEntity = principalEntity . GetType ( ) . GetProperty ( hasOne . EntityPropertyName ) ? . GetValue ( principalEntity ) ;
307+ return ( IIdentifiable ) relatedEntity ;
308+ }
309+ return relationship . Value ;
310+ }
311+
312+
294313 /// <inheritdoc />
295314 public virtual async Task < TEntity > UpdateAsync ( TId id , TEntity entity )
296315 {
0 commit comments