Как я могу преобразовать IQueryable<T> в ObjectQuery<T>?

Я пытаюсь применить совет в этом посте: Совет 22 - Как сделать так, чтобы действительно включить "Включить"

Он предлагает обходной путь для обеспечения активной загрузки в Entity Framework (4.2). Этот обходной путь включает приведение IQueryable к ObjectQuery.

Однако, когда я пытаюсь это сделать, как показано в посте, запрос возвращает ноль.

Мой запрос (ctx - это DbContext):

IEnumerable<Coupon> coupons =
    from x in ctx.Coupons
    where x.LanguageCode.Equals("EN", StringComparison.InvariantCultureIgnoreCase) && x.CategoryId == MainCategoryId && x.Date >= fromDate && x.Date <= toDate
    select x;

Это работает, как ожидалось.

Тем не менее, когда я использую,

IEnumerable<Coupon> coupons =
    (from x in ctx.Coupons
     where x.LanguageCode.Equals("EN", StringComparison.InvariantCultureIgnoreCase) && x.CategoryId == MainCategoryId && x.Date >= fromDate && x.Date <= toDate
     select x) as ObjectQuery<Coupon>;

это присваивает нуль "купонам".

Есть идеи, что я делаю не так?

2 ответа

Решение

Из комментариев к ответу:

Приведение к ObjectQuery<T> работает только тогда, когда запрос действительно ObjectQuery<T>, это не будет работать на любом другом IQueryable<T>, Так как вы используете DbContext вместо ObjectContextзапросы другого типа. Тем не менее, вам не нужно приводить к правильному типу, DbExtensions.Include методы расширения в System.Data.Entity пространство имен принимает любое IQueryable<T> введите и вызовите соответствующий базовый Include метод. Вы можете использовать это, избегать приведения и, таким образом, избегать явного указания типа запроса в вашем коде.

То, что вы делаете, эквивалентно этому

IEnumerable<Coupon> coupons =
    from x in ctx.Coupons
    where x.LanguageCode.Equals("EN", StringComparison.InvariantCultureIgnoreCase) && x.CategoryId == MainCategoryId && x.Date >= fromDate && x.Date <= toDate
    select x;

ObjectQuery<Coupon> converted = coupons as ObjectQuery<Coupon>;

, с coupons не нуль и converted ноль.

Что означает, что актерский состав терпит неудачу.
Это не решает вашу проблему, но, по крайней мере, определяет ее.

Возможно, вы используете другую версию Entity Framework?

Получение SQL-запроса из Entity Framework IQueryable помог мне решить эту проблему, чтобы удовлетворить немного другое требование: мне нужно получить доступ к TraceString И базовым параметрам, чтобы я мог ввести несколькоIQueryable<> выражения в .SqlQuery<>()

Когда вы осматриваете IQueryableво время сеанса отладки вы можете видеть, что внутри он использует ObjectQuery, но не наследует от ObjectQuery, поэтому вы не можете использовать его напрямую. Однако мы можем использовать Reflection для доступа к внутреннему объекту запроса.

Вот код Стива Фентона, заключенный в метод расширения:

    /// <summary>
    /// Extract the Internal Object Query from an IQueryable, you might do this to access the internal parameters for logging or injection purposes
    /// </summary>
    /// <remarks>Sourced from https://www.stevefenton.co.uk/2015/07/getting-the-sql-query-from-an-entity-framework-iqueryable/ </remarks>
    /// <typeparam name="T">Entity Type that is the target of the query</typeparam>
    /// <param name="query">The query to inspect</param>
    /// <returns>Object Query that represents the same IQueryable Expression</returns>
    public static System.Data.Entity.Core.Objects.ObjectQuery<T> ToObjectQuery<T>(this IQueryable<T> query)
    {
        // force the query to be cached, otherwise parameters collection will be empty!
        string queryText = query.ToString();
        queryText = queryText.ToLower(); // stop compiler from optimising this code away because we don't do anything with queryText parameter!

        var internalQueryField = query.GetType().GetProperties(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Where(f => f.Name.Equals("InternalQuery")).FirstOrDefault();
        var internalQuery = internalQueryField.GetValue(query);
        var objectQueryField = internalQuery.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Where(f => f.Name.Equals("_objectQuery")).FirstOrDefault();
        return objectQueryField.GetValue(internalQuery) as System.Data.Entity.Core.Objects.ObjectQuery<T>;
    }

Теперь ваш код может выглядеть так:

IEnumerable<Coupon> coupons =
    (from x in ctx.Coupons
     where x.LanguageCode.Equals("EN", StringComparison.InvariantCultureIgnoreCase) && x.CategoryId == MainCategoryId && x.Date >= fromDate && x.Date <= toDate
     select x).ToObjectQuery();
Другие вопросы по тегам