question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

String based Include

See original GitHub issue

In the older version of EF you were able to do something like, which is useful for dynamic scenarios.

        var query = db.CampaignCreatives.AsQueryable();
        foreach (string include in includes)
        {
            query = query.Include(include);
        };

Edited July-18 by @rowanmiller

Workaround

Here is some code that adds two string based overloads of Include.

  • One allows you to do EF6 style string includes - such as context.Blogs.Include("Posts") and context.Blogs.Include("Posts.Author.Photo").
  • The second overload allows you to make use of the C# 6 nameof feature when including multiple levels context.Blogs.Include(nameof(Post.Blog), nameof(Blog.Owner), nameof(Person.Photo))
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace ConsoleApplication5
{
    public static class Extensions
    {
        private static MethodInfo _include = typeof(EntityFrameworkQueryableExtensions)
                        .GetMethod("Include");

        private static MethodInfo _thenIncludeReference = typeof(EntityFrameworkQueryableExtensions)
            .GetMethods()
            .Where(m => m.Name == "ThenInclude")
            .Single(m => m.Name == "ThenInclude" &&
                         m.GetParameters()
                          .Single(p => p.Name == "source")
                          .ParameterType
                          .GetGenericArguments()[1].Name != typeof(ICollection<>).Name);

        private static MethodInfo _thenIncludeCollection = typeof(EntityFrameworkQueryableExtensions)
            .GetMethods()
            .Where(m => m.Name == "ThenInclude")
            .Single(m => m.Name == "ThenInclude" &&
                         m.GetParameters()
                          .Single(p => p.Name == "source")
                          .ParameterType
                          .GetGenericArguments()[1].Name == typeof(ICollection<>).Name);

        public static IQueryable<T> Include<T>(this IQueryable<T> query, string include)
        {
            return query.Include(include.Split('.'));
        }

        public static IQueryable<T> Include<T>(this IQueryable<T> query, params string[] include)
        {
            var currentType = query.ElementType;
            var previousNavWasCollection = false;

            for (int i = 0; i < include.Length; i++)
            {
                var navigationName = include[i];
                var navigationProperty = currentType.GetProperty(navigationName);
                if (navigationProperty == null)
                {
                    throw new ArgumentException($"'{navigationName}' is not a valid property of '{currentType}'");
                }

                var includeMethod = i == 0
                    ? _include.MakeGenericMethod(query.ElementType, navigationProperty.PropertyType)
                    : previousNavWasCollection
                        ? _thenIncludeCollection.MakeGenericMethod(query.ElementType, currentType, navigationProperty.PropertyType)
                        : _thenIncludeReference.MakeGenericMethod(query.ElementType, currentType, navigationProperty.PropertyType);

                var expressionParameter = Expression.Parameter(currentType);
                var expression = Expression.Lambda(
                    Expression.Property(expressionParameter, navigationName),
                    expressionParameter);

                query = (IQueryable<T>)includeMethod.Invoke(null, new object[] { query, expression });

                if (navigationProperty.PropertyType.GetInterfaces().Any(x => x.Name == typeof(ICollection<>).Name))
                {
                    previousNavWasCollection = true;
                    currentType = navigationProperty.PropertyType.GetGenericArguments().Single();
                }
                else
                {
                    previousNavWasCollection = false;
                    currentType = navigationProperty.PropertyType;
                }
            }

            return query;
        }
    }
}

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Comments:20 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
ajcvickerscommented, Nov 21, 2016

@eqbalsajadi String-based include was shipped in EF Core 1.1. That stackoverflow is out-of-date.

2reactions
gdoroncommented, Jul 18, 2016

Worth mentioning using this feature is risky if the include string is an unvalidated input coming from a user. A user can cause EF to query the entire DB and cause a DoS with a single request or cause SqlInjection.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Can a string-based Include alternative be created in Entity ...
Starting with v1.1.0, the string based include is now part of EF Core, so the issue and the below solution are obsolete. Original...
Read more >
EntityFrameworkQueryableExten...
Include <TEntity>(IQueryable<TEntity>, String). Specifies related entities to include in the query results. The navigation property to be included is specified ...
Read more >
NET 6 EF Core Load Related Data with Include(), ThenInclude ...
NET Jumpstart Course: https://www.udemy.com/course/net-core-31-web-api-entity-framework-core-jumpstart/?referralCode=CA390CA392FF8B003518 ...
Read more >
[Entity Framework] Using Include with lambda expressions
I'm currently working on a project that uses Entity Framework 4. Even though lazy loading is enabled, I often use the ObjectQuery.Include ......
Read more >
Connection String in Entity Framework Core
Connection string contain information about the data source that is being connected. This information varies from provider to provider, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found