Как я могу конвертировать IQueryable <T>в ObjectQuery <T>? - PullRequest
4 голосов
/ 16 декабря 2011

Я пытаюсь применить совет в этом посте: Совет 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>;

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

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

Ответы [ 3 ]

5 голосов
/ 17 декабря 2011

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

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

4 голосов
/ 16 декабря 2011

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

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?

0 голосов
/ 21 марта 2019

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

Когда вы проверяете IQueryable во время сеанса отладки, вы видите, что внутренне он использует ObjectQuery, но не Inherit из 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();
...