2

When I write expressions in our application as lambda expressions, I can usually make use of the following construct1:

dbContext.Contents<MyEntity>()

(dbContext is of a custom class.) Somehow, Linq1Entities/Entity Framework understands this to mean I am SELECTing items from the table matching MyEntity.

Now, I am constructing an expression by means of the System.Linq.Expressions classes. I have tried to replicate the above fragment like so:

Expression.Call(Expression.Constant(dbContext), contentsMethod)

contentsMethod has been initialized to the appropriate MethodInfo before by means of reflection.

Unfortunately, this does not work. Entity Framework complains that it cannot convert the dbContext object to SQL.

I have built an analogous expression of what I wanted as a lambda expression and looked at the resulting expression tree in the debugger. Interestingly, instead of a constant, the dbContext was modeled as a member access of what seemed to be a closure object.

Why is that? Why is a local variable dbContext represented by a member access to the closure in an expression, and why doesn't it alternatively work as a constant value? Does it matter that dbContext was a parameter of the enclosing method in my case?

My question is not how to solve the issue. I already did, by introducing the fragment shown above as an extra lambda expression whose body gets tied into my manually built expression.


1: An example of how that fragment is used is the following expression:

dbContext.Contents<MyEntity1>().Where(e1 => dbContext.Contents<MyEntity2>().Any(e2 => e1.Name == e2.Key))
5
  • dbContext is a database object which consists of different tables. A Select queries tables. The tables consists of columns with different datatypes. Usually the casting occurs on the field types of the columns. Commented May 17, 2017 at 13:17
  • Can you show a more complete example of how you use that dbContext.Contents<MyEntity>()? As is question seems very unclear, at least for me. I understand that you have dbContext parameter, you pass it to some lambda, it got captured and it's access becomes member-access of closure object. Commented May 17, 2017 at 13:19
  • @Evk: I have added a footnote with a short and anonymized, but complete expression that contains the indicated fragment. Commented May 17, 2017 at 13:53
  • I actually cannot reproduce this. I built an expression using Expression.Constant(dbContext) (to be exact - Expression.PropertyOrField(Expression.Constant(dbContext), "NameOfMyDbSetProperty"))), representing your exact Any query, and it works fine without complaining from EF side. Commented May 17, 2017 at 14:19
  • 1
    @Evk Actually it works for property/field, but not for method calls (for sure with generic instance methods like Set<T>) Commented May 17, 2017 at 14:39

1 Answer 1

1

dbContext is modeled as an access to a closure object because the lambda that defined it was closing over that variable. It wasn't using a constant value, it was closing over another value, so that's what it represented in the Expression. If it did anything else it wouldn't be properly representing the lambda.

When EF says that it can't convert an Expression to SQL it's simply saying that the authors of the code didn't anticipate the given expression, and didn't create a mapping of that pattern to SQL; they simply didn't anticipate people doing this (or didn't know how to map it to SQL, or couldn't, or didn't have the time to add that feature, whatever the case may be).

Sign up to request clarification or add additional context in comments.

3 Comments

Yes, but what's the conclusion in this case? EF can only handle dbContext when it is a member of something else, not if it is provided directly as a constant value?
@O.R.Mapper That or you did something else different in your case that it doesn't know how to map.
@O.R.Mapper That's the exact conclusion. The whole trick with expression tree translation is what type of expressions does the translator recognize / handle. As Servy mentioned in his answer, apparently your case is not recognized/handled by EF query translator.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.