We're updating the issue view to help you get more done. 

CloningExpressionVisitor.AdjustExpressionAfterCloning throws when called on cloned expression containing a subquery

Description

Repro:

 

public class MyCustomer

{ public int Id

{ get; set; }

}

public class MyOrder

{ public int Id
{ get; set; }

public int CustomerId { get; set; }
}

 

(...)

 

var customers = new List<MyCustomer>();
var orders = new List<MyOrder>();

var mainFromClause = new MainFromClause("outer", typeof(MyCustomer), Expression.Constant(customers));
var c = new QuerySourceReferenceExpression(mainFromClause);
var selectClause = new SelectClause(c);
var queryModel = new QueryModel(mainFromClause, selectClause);

var innerFromClause = new MainFromClause("inner", typeof(MyOrder), Expression.Constant(orders));
var o = new QuerySourceReferenceExpression(innerFromClause);
var innerSelectClause = new SelectClause(o);
var innerQueryModel = new QueryModel(innerFromClause, innerSelectClause);

var predicate = Expression.Equal(Expression.Property(c, "Id"), Expression.Property(o, "CustomerId"));
var where = new WhereClause(predicate);

innerQueryModel.BodyClauses.Add(where);
innerQueryModel.ResultOperators.Add(new CountResultOperator());

var orderby = new OrderByClause();
orderby.Orderings.Add(new Ordering(new SubQueryExpression(innerQueryModel), OrderingDirection.Asc));
queryModel.BodyClauses.Add(orderby);

 

var qsm = new QuerySourceMapping();
var clone = queryModel.Clone(qsm);

var adjusted = CloningExpressionVisitor.AdjustExpressionAfterCloning(orderby.Orderings[0].Expression, qsm);

 

throws:

 

Query source (from MyOrder inner in value(System.Collections.Generic.List`1[Microsoft.EntityFrameworkCore.Query.GearsOfWarQuerySqlServerTest+MyOrder])) has already been associated with an expression.
at Remotion.Linq.Clauses.QuerySourceMapping.AddMapping(IQuerySource querySource, Expression expression)
at Remotion.Linq.Clauses.MainFromClause.Clone(CloneContext cloneContext)
at Remotion.Linq.QueryModel.Clone(QuerySourceMapping querySourceMapping)
at Remotion.Linq.Clauses.ExpressionVisitors.CloningExpressionVisitor.VisitSubQuery(SubQueryExpression expression)
at Remotion.Linq.Clauses.Expressions.SubQueryExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Remotion.Linq.Clauses.ExpressionVisitors.CloningExpressionVisitor.AdjustExpressionAfterCloning(Expression expression, QuerySourceMapping querySourceMapping)

 

We use this pattern in EFCore to re-map expressions to the new (cloned) qsre structure. Works as expected unless there are subqueries involved. Is this the correct use of the API?

Activity

Show:
Michael Ketting
April 13, 2018, 6:14 AM

Hey , that a known issue (unfortunately) that didn't make it for v2.2 due to some brain-teaser issues that blew the timeline.

Assignee

Michael Ketting

Reporter

User known

Labels

Components

Fix versions

Priority

Normal
Configure