Closed
Description
When creating a projection using IQueryable.Select
I would expect that I can pass arbitrary variable from the context as a parameter to constructed object in the Select projection.
Currently, this throws an exception if I try to do this with the returned object although EF is OK if I do that with some of the inner objects (properties).
Is there any limitation why this does not work that I am missing or is this a bug ?
Steps to reproduce
class TestContext : DbContext
{
public DbSet<FromModel> Froms { get; set; }
}
class FromModel
{
public int Id { get; set; }
public string Name { get; set; }
}
class ToModel
{
public int Id { get; set; }
public WithParam WithParam { get; set; }
public ToModel() {}
public ToModel(object value) {}
}
class WithParam
{
public string Name { get; }
public WithParam(object us, string name)
{
Name = name;
//do something with `us`
}
}
private static Expression<Func<FromModel, ToModel>> CreateMapperWorking(object value) =>
//if we passed `value` to ToModel ctor EF Core would throw the exception
x => new ToModel
{
Skey = x.Skey,
//EF Core has no problem with this constructor parameter being a reference to arbitrary object
WithParam = new WithParam(value)
};
private static Expression<Func<FromModel, ToModel>> CreateMapperFailing(object value) =>
//we have passed the `value` to ToModel ctor so we will get the exception
x => new ToModel(value)
{
Skey = x.Skey,
//EF Core has no problem with this constructor parameter being a reference to arbitrary object
WithParam = new WithParam(value)
};
[Fact]
public async Task ExamplePassingTest()
{
using var ctx = new TestContext();
var v = new object();
_ = await ctx.Froms
.AsNoTracking()
.Select(CreateMapperWorking(v))
.FirstOrDefaultAsync();
Assert.True(true);
}
[Fact]
public async Task ExampleFailingTest()
{
using var ctx = new TestContext();
var v = new object();
_ = await ctx.Froms
.AsNoTracking()
.Select(CreateMapperFailing(v))
.FirstOrDefaultAsync();
//above throws System.InvalidOperationException
Assert.True(true);
}
From the failing test I get
System.InvalidOperationException : Client projection contains reference to constant expression of 'AutoMapperBug.Proof+<>c__DisplayClass10_0'. This could potentially cause memory leak. Consider assigning this constant to local variable and using the variable in the query instead. See https://go.microsoft.com/fwlink/?linkid=2103067 for more information.
System.InvalidOperationException : Client projection contains reference to constant expression of 'AutoMapperBug.Proof+<>c__DisplayClass10_0'. This could potentially cause memory leak. Consider assigning this constant to local variable and using the variable in the query instead. See https://go.microsoft.com/fwlink/?linkid=2103067 for more information.
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.ConstantVerifyingExpressionVisitor.VisitConstant(ConstantExpression constantExpression)
at System.Linq.Expressions.ConstantExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitMember(MemberExpression node)
at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
at System.Linq.Expressions.ExpressionVisitor.VisitNew(NewExpression node)
at System.Linq.Expressions.NewExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitAndConvert[T](T node, String callerName)
at System.Linq.Expressions.ExpressionVisitor.VisitMemberInit(MemberInitExpression node)
at System.Linq.Expressions.MemberInitExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block)
at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node)
at System.Linq.Expressions.BlockExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node)
at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.InjectEntityMaterializers(Expression expression)
at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitShapedQueryExpression(ShapedQueryExpression shapedQueryExpression)
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
at System.Linq.Expressions.Expression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at AutoMapperBug.Proof.NoAutoMapper2() in C:\Users\d61230\source\repos\Playground\AutoMapperBug\Proof.cs:line 141
--- End of stack trace from previous location where exception was thrown ---
Further technical details
EF Core version: 3.1.1
Database provider: Devart.Data.Oracle.EFCore 9.11.951
Target framework: .NET Core 3.1
Operating system: Windows 10
IDE: Visual Studio 2019 16.5