I am updating some projects to .Net10 EFCore 10 and Projectables 6 from .Net8 EFCore8 Projectables3, and hit this bug after changing the projectables version to 6.0.6.
If you call AsNoTracking() before selecting/projecting to a DTO or an anonymous type, the query throws argument exception.
Repro:
Any entity with a settable projectable (the #84 feature) will do:
public class Entity
{
public int Id { get; set; }
[Projectable(UseMemberBody = nameof(_ComputedWithBacking))]
[NotMapped]
public int ComputedWithBacking { get; set; }
private int _ComputedWithBacking => Id * 5;
}
db.Set<Entity>()
.AsNoTracking()
.Select(e => new { e.ComputedWithBacking })
.ToList();
Will throw
System.ArgumentException : Expression of type 'System.Linq.IQueryable`1[<>f__AnonymousType5`1[System.Int32]]'
cannot be used for parameter of type 'System.Linq.IQueryable`1[Entity]' of method
'System.Linq.IQueryable`1[Entity] Select[Entity,Entity](...)' (Parameter 'arg0')
Same thing with new SomeDto { ... } instead of an anonymous type. Without the AsNoTracking() it works fine. Re-ordering so AsNoTracking is after the Select also works.
What's going on:
ProjectableExpressionReplacer uses _disableRootRewrite to decide whether to append the Select<TEntity, TEntity> that populates settable projectables. A Select sets it to true, but since #132 AsNoTracking sets it back to false. The visitor walks the tree outside in, so for
db.Set<Entity>().AsNoTracking().Where(...).Select(e => new Dto { ... })
the Select is visited first and the AsNoTracking last, so the rewrite gets turned back on and appended to an IQueryable<Dto>, which throws an error.
Fix
Check out my PR (placeholder for PR when i make it). I'm not super familiar with this repo and used AI to help fix this bug. However I ran all the existing tests and they passed as well as adding tests for the bug I fixed.
I am updating some projects to .Net10 EFCore 10 and Projectables 6 from .Net8 EFCore8 Projectables3, and hit this bug after changing the projectables version to 6.0.6.
If you call
AsNoTracking()before selecting/projecting to a DTO or an anonymous type, the query throws argument exception.Repro:
Any entity with a settable projectable (the #84 feature) will do:
Will throw
Same thing with
new SomeDto { ... }instead of an anonymous type. Without theAsNoTracking()it works fine. Re-ordering so AsNoTracking is after the Select also works.What's going on:
ProjectableExpressionReplaceruses_disableRootRewriteto decide whether to append theSelect<TEntity, TEntity>that populates settable projectables. ASelectsets it to true, but since #132AsNoTrackingsets it back to false. The visitor walks the tree outside in, so forthe
Selectis visited first and theAsNoTrackinglast, so the rewrite gets turned back on and appended to anIQueryable<Dto>, which throws an error.Fix
Check out my PR (placeholder for PR when i make it). I'm not super familiar with this repo and used AI to help fix this bug. However I ran all the existing tests and they passed as well as adding tests for the bug I fixed.