Linq to SQL throwing a StackOverflowException?

I had my suspicions initially but can now confirm it You're combining two lambdas that have two completely different instances of their parameters. The parameter instances are not swappable, even if they have the same names and same types. They are effectively parameters in different scopes.

When you attempted to invoke one of the expressions with the wrong parameter object, chaos ensues, in this case, a stack overflow What you should be doing is create a new parameter instance (or reuse one) and rebind the bodies of your lambdas to use that new parameter. I suspect that will fix this. And to go a step further, you should properly combine these expressions by rebuilding them, rather than patching them together as method calls.

I doubt the query providers will like these as invocations any way Try this implementation of your And() and Or() methods along with this helper method to do the rebinding: public static Expression> And(this Expression> expression1, Expression> expression2) { // reuse the first expression's parameter var param = expression1.Parameters.Single(); var left = expression1. Body; var right = RebindParameter(expression2. Body, expression2.Parameters.Single(), param); var body = Expression.

AndAlso(left, right); return Expression. Lambda>(body, param); } public static Expression> Or(this Expression> expression1, Expression> expression2) { var param = expression1.Parameters.Single(); var left = expression1. Body; var right = RebindParameter(expression2.

Body, expression2.Parameters.Single(), param); var body = Expression. OrElse(left, right); return Expression. Lambda>(body, param); } private static Expression RebindParameter(Expression expr, ParameterExpression oldParam, ParameterExpression newParam) { switch (expr.

NodeType) { case ExpressionType. Parameter: var asParameterExpression = expr as ParameterExpression; return (asParameterExpression. Name == oldParam.Name)?

NewParam : asParameterExpression; case ExpressionType. MemberAccess: var asMemberExpression = expr as MemberExpression; return asMemberExpression. Update( RebindParameter(asMemberExpression.

Expression, oldParam, newParam)); case ExpressionType. AndAlso: case ExpressionType. OrElse: case ExpressionType.

Equal: case ExpressionType. NotEqual: case ExpressionType. LessThan: case ExpressionType.

LessThanOrEqual: case ExpressionType. GreaterThan: case ExpressionType. GreaterThanOrEqual: var asBinaryExpression = expr as BinaryExpression; return asBinaryExpression.

Update( RebindParameter(asBinaryExpression. Left, oldParam, newParam), asBinaryExpression. Conversion, RebindParameter(asBinaryExpression.

Right, oldParam, newParam)); case ExpressionType. Call: var asMethodCallExpression = expr as MethodCallExpression; return asMethodCallExpression. Update( RebindParameter(asMethodCallExpression.

Object, oldParam, newParam), asMethodCallExpression.Arguments. Select(arg => RebindParameter(arg, oldParam, newParam))); case ExpressionType. Invoke: var asInvocationExpression = expr as InvocationExpression; return asInvocationExpression.

Update( RebindParameter(asInvocationExpression. Expression, oldParam, newParam), asInvocationExpression.Arguments. Select(arg => RebindParameter(arg, oldParam, newParam))); case ExpressionType.

Lambda: var asLambdaExpression = expr as LambdaExpression; return Expression. Lambda( RebindParameter(asLambdaExpression. Body, oldParam, newParam), asLambdaExpression.Parameters.

Select(param => (ParameterExpression)RebindParameter(param, oldParam, newParam))); default: // you should add cases for any expression types that have subexpressions return expr; } } What the rebinding method does is searches for (by name) and returns an expression where all ParameterExpression within an expression tree are replaced with an instance of another ParameterExpression This does not modify the existing expressions but rebuilds the expression creating newly updated expressions when needed. In other words, it returns a new expression that should be used as a replacement of the one that you are rebinding The idea is to examine the Expression and determine what type it is. If it is a ParameterExpression check if it has the same name as the parameter we're looking for.

If it is, return our new parameter, otherwise return it as we shouldn't change it. If the expression is not a parameter, it will probably be an expression that contains subexpressions and would have to be replaced A BinaryExpression will have a Left operand and a Right operand, both expressions. They both need to be rebound since somewhere down their expression trees might be a parameter that needs replacing.

The Update() method will replace the current expression with a similar one with the new subexpressions. In this case, we only wanted to (potentially) update the Left and Right subexpressions The MethodCallExpression and InvocationExpression has the same idea but it's tree is slightly different.It has the Object expression (or Expression in the case of an invocation) which represents the instance (or delegate/lambda) that you want to be calling on. (The MethodCallExpression also has a MethodInfo which represents the instance method to call) They also have Arguments (all expressions) which are used as the arguments to the call.

These expressions potentially would need to be rebound You can think of the RebindParameter() method as a "super Update() method which updates parameters within an entire expression tree To further illustrate, an illustration to help visualize what the tree looks like and what changes. Note that since there are replacements occurring here, most of the subtrees will be new instances Now here's something I didn't realize was available, the ExpressionVisitor Wish I noticed it sooner. This will make the rebinder better to work with.

Rather than posting the full code here, here it is on pastebin Then to use it: public static Expression> And(this Expression> expression1, Expression> expression2) { // reuse the first expression's parameter var param = expression1.Parameters.Single(); var left = expression1. Body; var right = ParameterRebinder. Rebind(expression2.

Body, expression2.Parameters.Single(), param); var body = Expression. AndAlso(left, right); return Expression. Lambda>(body, param); } public static Expression> Or(this Expression> expression1, Expression> expression2) { var param = expression1.Parameters.Single(); var left = expression1.

Body; var right = ParameterRebinder. Rebind(expression2. Body, expression2.Parameters.Single(), param); var body = Expression.

OrElse(left, right); return Expression. Lambda>(body, param); }.

I had my suspicions initially but can now confirm it. You're combining two lambdas that have two completely different instances of their parameters. The parameter instances are not swappable, even if they have the same names and same types.

They are effectively parameters in different scopes. When you attempted to invoke one of the expressions with the wrong parameter object, chaos ensues, in this case, a stack overflow. What you should be doing is create a new parameter instance (or reuse one) and rebind the bodies of your lambdas to use that new parameter.

I suspect that will fix this. And to go a step further, you should properly combine these expressions by rebuilding them, rather than patching them together as method calls. I doubt the query providers will like these as invocations any way.

Try this implementation of your And() and Or() methods along with this helper method to do the rebinding: public static Expression> And(this Expression> expression1, Expression> expression2) { // reuse the first expression's parameter var param = expression1.Parameters.Single(); var left = expression1. Body; var right = RebindParameter(expression2. Body, expression2.Parameters.Single(), param); var body = Expression.

AndAlso(left, right); return Expression. Lambda>(body, param); } public static Expression> Or(this Expression> expression1, Expression> expression2) { var param = expression1.Parameters.Single(); var left = expression1. Body; var right = RebindParameter(expression2.

Body, expression2.Parameters.Single(), param); var body = Expression. OrElse(left, right); return Expression. Lambda>(body, param); } private static Expression RebindParameter(Expression expr, ParameterExpression oldParam, ParameterExpression newParam) { switch (expr.

NodeType) { case ExpressionType. Parameter: var asParameterExpression = expr as ParameterExpression; return (asParameterExpression. Name == oldParam.Name)?

NewParam : asParameterExpression; case ExpressionType. MemberAccess: var asMemberExpression = expr as MemberExpression; return asMemberExpression. Update( RebindParameter(asMemberExpression.

Expression, oldParam, newParam)); case ExpressionType. AndAlso: case ExpressionType. OrElse: case ExpressionType.

Equal: case ExpressionType. NotEqual: case ExpressionType. LessThan: case ExpressionType.

LessThanOrEqual: case ExpressionType. GreaterThan: case ExpressionType. GreaterThanOrEqual: var asBinaryExpression = expr as BinaryExpression; return asBinaryExpression.

Update( RebindParameter(asBinaryExpression. Left, oldParam, newParam), asBinaryExpression. Conversion, RebindParameter(asBinaryExpression.

Right, oldParam, newParam)); case ExpressionType. Call: var asMethodCallExpression = expr as MethodCallExpression; return asMethodCallExpression. Update( RebindParameter(asMethodCallExpression.

Object, oldParam, newParam), asMethodCallExpression.Arguments. Select(arg => RebindParameter(arg, oldParam, newParam))); case ExpressionType. Invoke: var asInvocationExpression = expr as InvocationExpression; return asInvocationExpression.

Update( RebindParameter(asInvocationExpression. Expression, oldParam, newParam), asInvocationExpression.Arguments. Select(arg => RebindParameter(arg, oldParam, newParam))); case ExpressionType.

Lambda: var asLambdaExpression = expr as LambdaExpression; return Expression. Lambda( RebindParameter(asLambdaExpression. Body, oldParam, newParam), asLambdaExpression.Parameters.

Select(param => (ParameterExpression)RebindParameter(param, oldParam, newParam))); default: // you should add cases for any expression types that have subexpressions return expr; } } What the rebinding method does is searches for (by name) and returns an expression where all ParameterExpression within an expression tree are replaced with an instance of another ParameterExpression. This does not modify the existing expressions but rebuilds the expression creating newly updated expressions when needed.In other words, it returns a new expression that should be used as a replacement of the one that you are rebinding. The idea is to examine the Expression and determine what type it is.

If it is a ParameterExpression, check if it has the same name as the parameter we're looking for. If it is, return our new parameter, otherwise return it as we shouldn't change it. If the expression is not a parameter, it will probably be an expression that contains subexpressions and would have to be replaced.

A BinaryExpression will have a Left operand and a Right operand, both expressions. They both need to be rebound since somewhere down their expression trees might be a parameter that needs replacing. The Update() method will replace the current expression with a similar one with the new subexpressions.

In this case, we only wanted to (potentially) update the Left and Right subexpressions. The MethodCallExpression and InvocationExpression has the same idea but it's tree is slightly different. It has the Object expression (or Expression in the case of an invocation) which represents the instance (or delegate/lambda) that you want to be calling on.

(The MethodCallExpression also has a MethodInfo which represents the instance method to call) They also have Arguments (all expressions) which are used as the arguments to the call. These expressions potentially would need to be rebound. You can think of the RebindParameter() method as a "super"-Update() method which updates parameters within an entire expression tree.

To further illustrate, an illustration to help visualize what the tree looks like and what changes. Note that since there are replacements occurring here, most of the subtrees will be new instances. Now here's something I didn't realize was available, the ExpressionVisitor.

Wish I noticed it sooner. This will make the rebinder better to work with. Rather than posting the full code here, here it is on pastebin.

Then to use it: public static Expression> And(this Expression> expression1, Expression> expression2) { // reuse the first expression's parameter var param = expression1.Parameters.Single(); var left = expression1. Body; var right = ParameterRebinder. Rebind(expression2.

Body, expression2.Parameters.Single(), param); var body = Expression. AndAlso(left, right); return Expression. Lambda>(body, param); } public static Expression> Or(this Expression> expression1, Expression> expression2) { var param = expression1.Parameters.Single(); var left = expression1.

Body; var right = ParameterRebinder. Rebind(expression2. Body, expression2.Parameters.Single(), param); var body = Expression.

OrElse(left, right); return Expression. Lambda>(body, param); }.

Hmm. That's a good point. I tried that change but I get the same result (StackOverflow).

I'm thinking that the translation to SQL handles both And/Or and AndAlso/OrElse the same because I've been using the root And/Or code for some time now with correct results (except in this case). Thanks. – Josh M.

Apr 22 at 3:17 @Josh: We'll have to see the full stack trace then. I doubt the provider would be choking on such a simple expression. Unless there are side effects in these properties, you shouldn't get a stack overflow using this expression.

Your expression builders are susceptible of causing problems due to how you build them. You're probably doing something improper elsewhere causing the overflow. – Jeff Mercado Apr 22 at 3:50 I can't seem to get the stack trace and I'm having trouble stepping into the .

NET Framework code. (See my other post here: stackoverflow. Com/questions/5751678/…) It's very frustrating!

– Josh M. Apr 22 at 3:52 @Josh: Can you try reverting your settings back to the way you had it where you got the stack overflows? If necessary, revert back to the default settings and possibly rebooting?

I can't give you a definitive answer on how you can resolve that. That is the sort of problem is difficult to debug or give insight on without access to the same environment and code to reproduce. – Jeff Mercado Apr 22 at 4:02 - here is a sample project which reproduces the issue: cid-0ede5d21bdc5f270.office.live.Com/self.

Aspx/Public/Forums/… – Josh M. Apr 227 at 14:13.

After reviewing the information you provided I'm a bit stumped. If you're willing to humor a shot in the dark, try the following code: using (XYZDataContext context = new XYZDataContext()) { var queryableThings = context.Things.AsQueryable(); var result = queryableThings. Where(expression); int count = result.Count(); } If this doesn't reveal anything I'd start suspecting side-effects of the Thing entity's property getter methods.

Maybe some interaction results in a recursion? Are you using Mono by chance? Not that it isn't possible but I'd be really surprised if this is a bug in the LinqToSQL provider.

Thanks. I tried this and got the same result. Of course if I do context.Things.ToList().

Where(expression).Count() then it works fine. – Josh M. Apr 21 at 15:43 I'm at a loss then.

From what you said above it seems like the exception occurs when expression is being converted into sql. Which is kinda shocking to me. If I think of anything I'll post it.

And when you figure it out please do add it here. Good Luck! – Sorax Apr 21 at 16:22 FYI: Removing one of the inner or'd clauses, it works fine.So having both inner or'd clauses is breaking the translation from LINQ to SQL, somehow.

– Josh M. Apr 21 at 17:08 - here is a sample project which reproduces the issue: cid-0ede5d21bdc5f270.office.live.Com/self. Aspx/Public/Forums/… – Josh M.

Apr 26 at 14:13 Alright. I got the code going on my machine and am receiving the overflow exception. I'll report back once I get a chance to dig into it.

– Sorax Apr 26 at 20:22.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions