@@ -82,6 +82,7 @@ public DefaultEntityRepository(
82
82
public virtual IQueryable < TEntity > Get ( )
83
83
=> _dbSet ;
84
84
85
+ /// <inheritdoc />
85
86
public virtual IQueryable < TEntity > Select ( IQueryable < TEntity > entities , List < string > fields )
86
87
{
87
88
if ( fields ? . Count > 0 )
@@ -228,16 +229,16 @@ private void AttachHasMany(TEntity entity, HasManyAttribute relationship, IList
228
229
var relatedList = ( IList ) entity . GetType ( ) . GetProperty ( relationship . EntityPropertyName ) ? . GetValue ( entity ) ;
229
230
foreach ( var related in relatedList )
230
231
{
231
- if ( _context . EntityIsTracked ( related as IIdentifiable ) == false )
232
+ if ( _context . EntityIsTracked ( ( IIdentifiable ) related ) == false )
232
233
_context . Entry ( related ) . State = EntityState . Unchanged ;
233
234
}
234
235
}
235
236
else
236
237
{
237
238
foreach ( var pointer in pointers )
238
239
{
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 ;
241
242
}
242
243
}
243
244
}
@@ -266,31 +267,49 @@ private void AttachHasManyThrough(TEntity entity, HasManyThroughAttribute hasMan
266
267
267
268
/// <summary>
268
269
/// This is used to allow creation of HasOne relationships when the
269
- /// independent side of the relationship already exists.
270
270
/// </summary>
271
271
private void AttachHasOnePointers ( TEntity entity )
272
272
{
273
- var relationships = _jsonApiContext . HasOneRelationshipPointers . Get ( ) ;
273
+ var relationships = _jsonApiContext
274
+ . HasOneRelationshipPointers
275
+ . Get ( ) ;
276
+
274
277
foreach ( var relationship in relationships )
275
278
{
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 ) ;
278
282
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 )
281
285
{
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
287
290
{
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 ;
290
296
}
297
+
291
298
}
292
299
}
293
300
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
+
294
313
/// <inheritdoc />
295
314
public virtual async Task < TEntity > UpdateAsync ( TId id , TEntity entity )
296
315
{
0 commit comments