Как я могу преобразовать 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();