3

I've recently noticed something odd, navigation properties on an Entitiy do not implement IQueryable, while as far as i know retrieving a single entity and then chaining operators on navigation property may result in many (1 per item) calls to the database, from the generated code i've seend having one large query with subqueries results (when possible) in a single large query.

However i'm wondering about how it works because the overloads available in a subquery are the same as the ones which would be called on the navigation property outside of the subquery. Question 1: my guess is that , even if it's on IEnuerable, while the any call itself is part of the expression passed to where, it's then build into the single expression tree generated in where and parsed there and not as a separate expression (since it isn't an expression by itself), is this correct?

Qestion 2: If #1 is correct, how does this work if you create code outside from the expression which may only be made in a delegate at runtime (for example, how would that work if i passed PredicateExprEntityTwo.Compile(), in q5, would that not compile and fail at runtime because the compiler doesn't have knowledge of the usage of the func within an expression at compile time?

Question 3: Assuming i've got #1 and #2 correct, what's the advantage of this design vs taking an expression there? The disadvantage i've ran into is that for business validation i was thinking of having a set of predicates with business logic incorporated in them to filter the same type of entities in many places in a program, however i may want to use those in subqueries too and assuming #2 is right it may be unfeasible to reuse the same one?

I'm sorry if the questions sound a bit confusing but i've only noticed last week that i had IEnumerables overload called in subqueries yet still a single EF query as an output and i'm very curious about how this may work.

public class Class1
{
    void Test()
    {
        Func<Entity1, bool> PredicateFuncEntityOne = i => i.Id == 2;
        Expression<Func<Entity1, bool>> PredicateExprEntityOne = i => i.Id == 2;
        Func<Entity2, bool> PredicateFuncEntityTwo = i => i.Id == 2;
        Expression<Func<Entity2, bool>> PredicateExprEntityTwo = i => i.Id == 2;
        using (var Context = new TestModelContainer())
        {
            // Works as this expects an expression
            var q1 = Context.Entity1Set.Where(PredicateExprEntityOne);
            // Works but would call the IEnumerable version
            var q2 = Context.Entity1Set.Where(PredicateFuncEntityOne);
            // This compiles, any on item.Entity2 expects a func on IEnumerable, not IQueryable overload
            var q3 = Context.Entity1Set.Where(item => item.Entity2.Any(PredicateFuncEntityTwo));
            // This fails for the reason mentioned above
            var q4 = Context.Entity1Set.Where(item => item.Entity2.Any(PredicateExprEntityTwo));
            // Does this work and if so how is it possible?
            var q5 = Context.Entity1Set.Where(item => item.Entity2.Any(PredicateExprEntityTwo.Compile()));
        }
    }
}
Ronan Thibaudau
  • 301
  • 2
  • 6

1 Answers1

0

Q1 : I too think this is right.

Q2 : Yes, if you pass Func or any delegate into expression, then compiling of query will fail.

I am not sure about Q3.

But some time back, I had similiar problem while playing around in EF. And I found that casting those relational properties to IQueryable and calling methods Expressions supprisingly worked. But it might be a fluke.

Euphoric
  • 12,645
  • 1
  • 30
  • 44
  • Hello, While this is comforting it doesn't really answer my questions, i'm really looking for spec-level answers on this as i'm about to base some strong program design decisions around it and while i could test around it i'd rather have a clear explanation of the hows and whys (specially because what i suggest is counter intuitive compared to marking those as IQueryable and i'm really wondering if i'm missing something). – Ronan Thibaudau May 09 '11 at 23:24