我如何转换IQueryableObjectQuery< T>

本文关键字:IQueryable ObjectQuery 转换 何转换 | 更新日期: 2023-09-27 18:18:17

我试着在这篇文章中应用建议:技巧22 -如何使Include真正包含

它建议了一个解决方案,以确保在实体框架(4.2)中的急切加载工作。这个解决方法包括将IQueryable转换为ObjectQuery。

然而,当我尝试这样做时,如帖子所示,查询返回null。

我的查询是(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>;

它将null赋值给"coupon "。

知道我做错了什么吗?

我如何转换IQueryable<T>ObjectQuery< T>

从评论到答案:

转换到ObjectQuery<T>只在查询确实是ObjectQuery<T>时有效,它不会在任何其他IQueryable<T>上工作。由于您使用的是DbContext而不是ObjectContext,因此查询是不同类型的。但是,您不需要转换为正确的类型,System.Data.Entity名称空间中的DbExtensions.Include扩展方法接受任何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为空。

表示转换失败。
这并不能解决你的问题,但至少能识别问题。

也许你正在使用不同版本的实体框架?

从实体框架IQueryable获取SQL查询帮助我解决了这个问题,以满足稍微不同的需求,我需要访问TraceString 底层参数,这样我就可以注入一些IQueryable<>表达式到.SqlQuery<>()

当您在调试会话期间检查IQueryable时,您可以看到它在内部使用ObjectQuery,但它没有从ObjectQuery继承,因此您不能直接转换它。但是,我们可以使用反射来访问内部查询对象。

这是Steve Fenton的代码包装成一个扩展方法:

    /// <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();