question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

InvalidOperationException when using Poco-Class as Query Parameter

See original GitHub issue

This 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:closed
  • Created 3 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
sdanylivcommented, Oct 13, 2020

Will handle that, thanks for reporting.

0reactions
BenKmanncommented, Oct 13, 2020

@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).

public enum TestEnum
		{
			a,
			b,
			c,
			d
		}

		[Table]
		class MasterClass
		{
			[Column] [PrimaryKey] public int Id1 { get; set; }
			[Column] [PrimaryKey] public int Id2 { get; set; }
			[Column] public string? Value { get; set; }
			public TestEnum? Value2 { get; set; }

			[Column] public byte[]? ByteValues { get; set; }

			[Association(ThisKey = nameof(Id1), OtherKey = nameof(DetailClass.MasterId))]
			public List<DetailClass> Details { get; set; } = null!;

			[Association(QueryExpressionMethod = nameof(DetailsQueryImpl))]
			public DetailClass[] DetailsQuery { get; set; } = null!;

			static Expression<Func<MasterClass, IDataContext, IQueryable<DetailClass>>> DetailsQueryImpl()
			{
				return (m, dc) => dc.GetTable<DetailClass>().Where(d => d.MasterId == m.Id1 && d.MasterId == m.Id2 && d.DetailId % 2 == 0);
			}
		}

And the Mapping code is now easier and i can reproduce it with this mapping code as well

db.MappingSchema
  .GetFluentMappingBuilder()
  .Entity<MasterClass>()
  .Property(m => m.Value2)
	.HasSkipOnInsert(true)
	.HasSkipOnUpdate(true)
	.IsExpression(x => x.Value, false);

var container = new MasterClass();
container.Value2 = TestEnum.a;
var enumValue = container.Value2;

// this works
var something = (from x in db.GetTable<MasterClass>()
				 where x.Value2 != enumValue
				 select x).ToList();

// this doesn't
var something2 = (from x in db.GetTable<MasterClass>()
                 where x.Value2 != container.Value2
				  select x).ToList();
Read more comments on GitHub >

github_iconTop Results From Across the Web

The type parameter 'POCO Class' in ExecuteFunction is ...
InvalidOperationException : The type parameter 'POCO' in ExecuteFunction is incompatible with the type 'EFComplexType' returned by the function.
Read more >
Using Query String Parameters with Minimal APIs
It seems that we cannot bind complex objects from query string parameters, as we get an Exception: System.InvalidOperationException: No public ...
Read more >
2.19 breaks projections? - Drivers & ODMs
The InvalidOperationException indicates that the driver attempted to deserialize the _v field, but found the BSON EndOfDocument marker.
Read more >
Parameter binding in Minimal API applications
Parameter binding is the process of converting request data into strongly typed parameters that are expressed by route handlers.
Read more >
How to use parameter binding in minimal APIs in ASP.NET ...
We'll use this ASP.NET Core Web API project to work with parameter binding in the sections below. What is parameter binding? Parameter binding ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found