I am strugling to understand why the query is retuning this error when I perform the following statement:
SelectFor(x => x.Id == id, true, false, "Scope.Hiring.Scopes")
The string in the above statement are the entities to include.
SelectFor Method:
public virtual TEntity SelectFor(Expression<Func<TEntity, bool>> predicate, bool noTracking = true, bool selectInactiveItems = false, params string[] entitiesToLoad)
{
var query = this.LoadRelatedEntities(this.transaction.Context.Set<TEntity>().AsQueryable(), entitiesToLoad);
query = query.Where(x => x.OwnerId == ownerId).Where(predicate);
if (!selectInactiveItems)
{
query = query.Where(x => x.Active);
}
if (noTracking)
{
query = query.AsNoTracking();
}
return query.FirstOrDefault();
}
Include Method
protected IQueryable<TEntity> LoadRelatedEntities(IQueryable<TEntity> query, params string[] entitiesToLoad)
{
if (entitiesToLoad != null && entitiesToLoad.Count() > 0)
{
foreach (var entityToLoad in entitiesToLoad)
{
query = query.Include(entityToLoad);
}
}
return query;
}
It seems quite easy thing to do, but it's taking my time and patience.
You use AsNoTracking
in your query. Because of this, EF doesn't keep track of the entities it materializes. This means that when it fetches Scope
s from the database it will create multiple objects for each "identical" scope. This definitely happens here because of the circular query pattern Scope.Hiring.Scopes
.
However, EF does perform relationship fixup while building the object graph, i.e. it populates navigation properties with entities that are materialized so that f.e. each Scope
object will have a Hiring
reference. While doing this, I figure it tries to assign a duplicated Scope
object to a Hiring
object that already has this object.
Solution: remove the AsNoTracking
or remove the circular query: Scope.Hiring
instead of Scope.Hiring.Scopes
.