1

I use Entity framework 6. I have a Transaction object with several navigation properties. It is easy to implement eager loading using multiple Include.

 var aa = db.Transactions.Include(p => p.Account).Include(p => p.Instrument); 

How can I implement the same if the fields to be included are parameters?

var aa = db.Transactions.IncludeMore(delegatesToBeIncluded); 

If delegatesToBeIncluded is null then there is nothing to be included.

https://stackoverflow.com/a/38823723/5852947 This is similar what I want but it uses string instead of delegates.

https://stackoverflow.com/a/35889204/5852947 This is also interesting.

How to pass lambda 'include' with multiple levels in Entity Framework Core? This focuses on multiple level (I have one level)

https://stackoverflow.com/a/52156692/5852947 This is promising also.

Which direction should I go?

Revision 1: Why I need this? Based on the elements of aa new objects will be created. I realized that at each object creation EF reads the DB (lazy loading is used). It is just 50 ms, but it is repeated n times. This function is implemented in a template class, so Transactions is also a parameter.

Revision 2: In the full code there is filtering (pagination to be exact), and ToList() at then end. The tricky part that it is implemented in a template function. dbTableSelector is a delegate: readonly Func<MainDbContext, DbSet<TDbTable>> dbTableSelector;

 var myList = dbTableSelector(db).Where(WhereCondition). Skip(numberOfSkippedRows).Take(PageSize).OrderBy(OrderByCondition).ToList(); 

After that I transform each element of myList to another type of object. This is where lazy loading is activated one by one for each element. That is why I try to use Include. If dbTableSelector(db) returns Transactions I have to Include different elements when it returns let us say Instruments. So IncludeMore should have a List parameter which defines the fields to be included.

10
  • What are you trying to do? First of all, you aren't loading anything. aa is a queryable that hasn't executed yet. If the final query's Select touches on any related entities, they'll be loaded as well, even without Include. Second, since aa is a queryable, you can "append" Include or Where calls as needed, eg foreach(var exp in expressions){ aa=aa.Include(exp);} Commented Aug 24, 2020 at 17:24
  • The only reason you'd need to append Include calls dynamically would be if you were trying to create a dynamic query generator without actually knowing what the type is. Since you already know what the type is though, trying to "parameterize" the calls will end up more verbose than simply using the Include calls you need in each case. Commented Aug 24, 2020 at 17:27
  • That's not necessarily true. Back in March, I had to deal with a method which was called from a million places and the Include()s were the worst compromise you could ask for. It had to be the union of everything since the poor method could not be certain which linked entity might be used. Commented Aug 24, 2020 at 17:30
  • @PanagiotisKanavos see Revision 1 Commented Aug 24, 2020 at 18:05
  • This simply repeats what the question says so all the comments still apply. It isn't even accurate, precisely because aa is still an incomplete query. You need to either iterate over it or use ToList(), ToArray() etc to execute it. If you write a Select that needs the related entities, they'll be loaded. Commented Aug 25, 2020 at 6:51

2 Answers 2

1

Based on: https://learn.microsoft.com/en-us/answers/questions/1315166/parameterizing-theninclude()-in-entity-framework

public static class IQueryableExtensions { public static IQueryable<T> IncludeMultiple<T>(this IQueryable<T> query, params Expression<Func<T, object?>>[] includes) where T : class { foreach (var include in includes) { query = query.Include(include); } return query; } } 

Usage:

var query = db.Entity.IncludeMultiple(n => n.NavProp1, n => n.NavProp2); 
Sign up to request clarification or add additional context in comments.

Comments

0

Here is the solution. It is based on this.

public static class IQueryableExtensions { public static IQueryable<T> IncludeMultiple<T, TProperty>(this IQueryable<T> query, Expression<Func<T, TProperty>>[] includeDelegates) where T : class { foreach (var includeDelegate in includeDelegates) query = query.Include(includeDelegate); return query; } } 

This is the calling:

var pathsA = new Expression<Func<ViewTransaction, object>>[2] { p => p.Account, p => p.Instrument }; var pathsB = new Expression<Func<ViewTransaction, object>>[1] { p => p.Account}; var pathsC = Array.Empty<Expression<Func<ViewTransaction, object>>>(); var a = db.ViewTransactions.IncludeMultiple(pathsA).Single(e => e.Id == 100); 

1 Comment

Not quite correct yet. To enable pass the includes expressions directly in the params, remove generic type param TProperty and change to object? in param expression type. Based on this: learn.microsoft.com/en-us/answers/questions/1315166/…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.