2

In EF, when you want to include a navigation property in the result of a query, you use Include(). Since some queries require calling this more than once, I tried to create a generic wrapper around this concept:

public IQueryable<T> FindAll<P>(params Expression<Func<T, P>>[] predicates) where P : class {
  var entities = AllEntities();
  foreach (var p in predicates) entities = entities.Include(p);
  return entities;
}

And call it as such:

var customers = FindAll(q => q.Orders, q => q.Invoices, q => q.Contacts);

Questions:

  1. The function compiles, but when I call it: "The type arguments for method cannot be inferred from the usage. Try specifying the type arguments explicitly." What am I doing wrong?
  2. If I get it to work, can I call Include() the first time: var customers = FindAll(q => q.Orders, q => q.Invoices); and then again later in a separate step: customers = customers.Include(p => p.Invoices); or will that result in poor performance such that I should do the includes in one go?

EDIT:
JonSkeet's answer is correct, of course, and yet there is this solution which seems to do what I want. Not sure why it works however. Is it because of the Aggregate() function?

1
  • Would making it Func<T, object> work? Commented Oct 24, 2012 at 11:51

1 Answer 1

4

Fundamentally, I think you've got a problem - assuming that q.Orders, q.Invoices and q.Contacts return different types, you can't express what you want to happen. You probably want something like:

entities.Include<Parent, Order>(p => p.Order);
entities.Include<Parent, Invoice>(p => p.Invoices);
entities.Include<Parent, Contact>(p => p.Contacts);

... so you want a different value for P for each predicate. But you're calling a single method, providing a single type argument for P.

It's not clear that this is really giving you much benefit anyway... couldn't you just write:

var customers = AllEntities().Include(q => q.Orders)
                             .Include(q => q.Invoices)
                             .Include(q => q.Contacts);

I'd say that's clearer and it gets round the "multiple type parameters" problem.

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

7 Comments

Yes that's what I'm doing now, but its in a generic repository and I wanted to be able to specify which of those navigation properties to pull in together with a query; and of course different entities have different navigation properties. If there's no good way to do it I'll carry on using the normal approach.
@BobbyB: Do you understand may point about why your current approach can't work? What type argument would you want to use for P?
yes what I meant is that I'm currently doing it using your "alternative way" (in your second code block). The way I wanted to do it doesn't work for the exact reason you explained - P is multiple types i.e. Orders, Invoices and Contacts.
I agree with your comments, but how does it compare to this answer which seems to do what I want? Not sure of the difference here?
@BobbyB: The difference is that that question only took Expression<Func<T, object>> expressions. I'm somewhat surprised it works at all, but if it helps you, that's fine. It doesn't change my point that the reason your version isn't working is that you're trying to take multiple Func<T, P> projections (not really predicates, btw) but with different P types, all in one call.
|

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.