Hi again. I think this got broken after .net core and/or ef core update to 2.0.6.
So I have this code in controller:
var u = await _dbContext.Users.Where(new UserBasic(4526660).ToExpression()).ToListAsync();
Where UserBasic is specification class. See attached file "Specification pattern". When I run this I get the error:
ArgumentException: Property 'Int32 UserId' is not defined for type 'GLXY2.Data.Entities.UserGroup.User'
Parameter name: property
System.Linq.Expressions.Expression.Property(Expression expression, PropertyInfo property)
// Here framework code logs //
GLXY2.Patterns.SpecificationPattern.CombineExpressions(Expression<Func<T, bool>> left, Expression<Func<T, bool>> right, bool and) in SpecificationPattern.cs
+
exprBody = (BinaryExpression)new ParameterReplacer(paramExpr).Visit(exprBody);
GLXY2.Patterns.SpecificationPattern.CombineAndExpressions(Expression<Func<T, bool>> left, Expression<Func<T, bool>> right) in SpecificationPattern.cs
+
return CombineExpressions(left, right, true);
GLXY2.Models.Specifications.UserGroup.UserBasic.ToExpression() in UserBasic.cs
+
return CombineAndExpressions(expression, expression);
GLXY2.Controllers.HomeController+<Index>d__7.MoveNext() in HomeController.cs
+
var u = await _dbContext.Users.Where(new UserBasic(4526660).ToExpression()).ToListAsync();
// Here framework code logs //
So I'v tried many ways to debug this and only problem is with navigation property which works ok when in one expression and get lost when gets combined. Before I had something else with this thing and it's kind of disaster. I just can't trust what I code. Today it works and tomorrow it may not. Can you help me?
EF Core version: latest stable version 2.0.3?
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: Windows 10
IDE: Visual Studio 2017 Community latest stable version


When I changed code of CombineExpressions to this it became working again. I don't know anything about it, but why ParameterReplacer that worked well before, and which is well known on the web doesn't anymore? And am I safe with this new code? What is the parameter and can be there more than one while I combine only expressions of same T? And I don't know is this a bug in EF or C# language.

It looks like you have a call to Where in there, which would have a quoted lamba expression argument, which of course has its own parameter. Your parameter replacing visitor replaces all parameters outright. What you would want to do is pass in the parameter that needs to be replaced in addition to the new parameter, and then in VisitParameter, return parameter == targetParameter ? newParameter : parameter. You would then create an instance that replaces all instances of the right expression鈥檚 prameter with the left expression鈥檚 parameter.
Your ParameterReplacer is incorrect. That is the reason it does not work.
In the ParameterReplacer whenever you are visiting a parameter node you are replacing it with _parameter which is of type user.
The expression you are calling parameter replacer contains another lambda inside. like this one u.MyIgnoredUsers.Where(ign => ign.UserId == _currentUserId).Count() == 0
There is lambda expression inside the Where which contains own parameter ign. By blinding replacing it with _parameter (of type User) in parameter replacer, you eventually caused a member expression of u.UserId which does not exist hence you get exception that UserId is not defined on User. Essentially the ExpressionTree is getting corrupted by ParameterReplacer.
To correctly replace one expression with another expression in ExpressionTree, you should utilize both the nodes.
You would need some code like this:
https://github.com/re-motion/Relinq/blob/76e03ac938a5581b60d67b3032fb7908bf929177/Core/Parsing/ExpressionVisitors/ReplacingExpressionVisitor.cs#L42-L57
In simple step, whenever you encounter old expression, return the replacement. You can figure out old & new parameter in CombineExpressions easily using left/right.Parameters.
@tuespetre - Sorry for posting same answer. I had stale tab open for few hours and i did not see it was already answered till I posted comment.
Most helpful comment
@tuespetre - Sorry for posting same answer. I had stale tab open for few hours and i did not see it was already answered till I posted comment.