InvalidOperationException when using Poco-Class as Query Parameter
See original GitHub issueThis code:
var container = new MyPocoClass();
container.MyStringProperty = "Hello World";
var something = (from x in db.MyPocoClass
where x.MyStringProperty != container.MyStringProperty
select x).ToList();
Generates this Exception:
Exception message: Code supposed to be unreachable
Stack trace:
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteUnaryExpression(Expression expr, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpression(Expression node, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.RewriteExpressionFreeTemps(Expression expression, Stack stack)
at System.Linq.Expressions.Compiler.StackSpiller.Rewrite[T](Expression`1 lambda)
at System.Linq.Expressions.Expression`1.Accept(StackSpiller spiller)
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator)
at LinqToDB.Linq.Builder.ExpressionBuilder.CreateParameterAccessor(IDataContext dataContext, Expression accessorExpression, Expression originalAccessorExpression, Expression dbDataTypeAccessorExpression, Expression expression, ParameterExpression expressionParam, ParameterExpression parametersParam, ParameterExpression dataContextParam, String name)
at LinqToDB.Linq.Builder.ExpressionBuilder.PrepareConvertersAndCreateParameter(ValueTypeExpression newExpr, Expression valueExpression, String name, ColumnDescriptor columnDescriptor, BuildParameterType buildParameterType)
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildParameter(Expression expr, ColumnDescriptor columnDescriptor, Boolean forceConstant, BuildParameterType buildParameterType)
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertToSql(IBuildContext context, Expression expression, Boolean unwrap, ColumnDescriptor columnDescriptor, Boolean isPureExpression)
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertCompare(IBuildContext context, ExpressionType nodeType, Expression left, Expression right)
at LinqToDB.Linq.Builder.ExpressionBuilder.ConvertPredicate(IBuildContext context, Expression expression)
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSearchCondition(IBuildContext context, Expression expression, List`1 conditions, Boolean isNotExpression)
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildWhere(IBuildContext parent, IBuildContext sequence, LambdaExpression condition, Boolean checkForSubQuery, Boolean enforceHaving)
at LinqToDB.Linq.Builder.WhereBuilder.BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
at LinqToDB.Linq.Builder.MethodCallBuilder.BuildSequence(ExpressionBuilder builder, BuildInfo buildInfo)
at LinqToDB.Linq.Builder.ExpressionBuilder.BuildSequence(BuildInfo buildInfo)
at LinqToDB.Linq.Builder.ExpressionBuilder.Build[T]()
at LinqToDB.Linq.Query`1.CreateQuery(IDataContext dataContext, Expression expr)
at LinqToDB.Linq.Query`1.GetQuery(IDataContext dataContext, Expression& expr)
at LinqToDB.Linq.ExpressionQuery`1.GetQuery(Expression& expression, Boolean cache)
at LinqToDB.Linq.ExpressionQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at DbTasks.Program.Main(String[] args) in C:\DbTasks\Program.cs:line 104
But this Code works:
var container = new MyPocoClass();
container.MyStringProperty = "Hello World";
string myTestString = container.MyStringProperty;
var something = (from x in db.MyPocoClass
where x.MyStringProperty != myTestString
select x).ToList();
Apparently Linq2Db tries to translate the property of the POCO, although I only want the content. As long as i assign it to a variable before it is happy. MyPocoClass.MyStringProperty is mapped with this code, which is the reason it crashes apparently:
propertybuilder.IsExpression(x => Sql.Property<object>(x, otherPropertyNameWhichIsMappedToADbColumn), false);
We do that, because the Property is only there for convenience and this mapping helps us to have two properties for this one column. It normally works. Now I think, because “MyStringProperty” is not a column, he crashes, when he sees it as a Value on the right side. And apparently the Expressionbuilder tries to build this property as “a column” instead of “a value”.
If i remove the mapping code
// propertybuilder.IsExpression(x => Sql.Property<object>(x, otherPropertyName), false);
and make it a normal Db-Column, the Expressionbuilder is happy and accepts “container.MyStringProperty” and correctly makes it to a parameter in the query.
I think this is a bug, because the Expressionbuilder is apparently able to build a query with this property and he shoud not even try to build an expression out of container.MyStringProperty.
Environment details
linq2db version: 3.1.3 Database Server: Sql-Server 2019 Database Provider: Sql-Server 2019 Operating system: Windows 10 .NET Framework: 4.5.2
Issue Analytics
- State:
- Created 3 years ago
- Comments:7 (3 by maintainers)
Will handle that, thanks for reporting.
@sdanyliv i have modified the example a little, to get it closer to my real problem. We have columns mapped to an enum AND to the string Value we get from the db. So we have the Option to use both, because 95% of the Values in the DB are in the enum and for the rest we have the string-property.
So same Example as before, but “Value2” is our NoColumn Enum Property (instead of string).
And the Mapping code is now easier and i can reproduce it with this mapping code as well