如何将 IQueryable转换为到 ObjectQuery

发布于 2024-12-21 11:41:32 字数 1018 浏览 1 评论 0原文

我正在尝试应用这篇文章中的建议: 提示 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>;

它会为“优惠券”分配一个空值。

知道我做错了什么吗?

I'm trying to apply the advice in this post: Tip 22 - How to make Include really Include

It suggests a workaround for ensure eager loading works in the Entity Framework (4.2). That workaround involves casting the IQueryable to an ObjectQuery.

However, when I attempt this, as shown in the post, the query returns a null.

My query is (ctx is a 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;

That works as expected.

However, when I use,

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>;

it assigns a null to "coupons".

Any idea what I'm doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蓝眼睛不忧郁 2024-12-28 11:41:32

从评论到答案:

转换为 ObjectQuery 仅当查询确实是 ObjectQuery 时才有效,它不适用于任何其他<代码>IQueryable。由于您使用的是 DbContext 而不是 ObjectContext,因此查询属于不同类型。但是,您不需要转换为正确的类型,System.Data.Entity 命名空间中的 DbExtensions.Include 扩展方法接受任何 IQueryable类型。 类型,并调用适当的底层 Include 方法。您可以使用它,避免强制转换,从而避免在代码中显式指定查询的类型。

From the comments to an answer:

Casting to an ObjectQuery<T> only works when the query really is an ObjectQuery<T>, it won't work on any other IQueryable<T>. Since you're using a DbContext instead of an ObjectContext, the queries are of a different type. However, you do not need to cast to the correct type, the DbExtensions.Include extension methods in the System.Data.Entity namespace accept any IQueryable<T> type, and call the appropriate underlying Include method. You can use this, avoid the cast, and thereby avoid explicitly specifying the query's type in your code.

指尖微凉心微凉 2024-12-28 11:41:32

您所做的与此等效

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 不为 null 并且 converted null。

这意味着演员阵容失败。
这并不能解决您的问题,但至少可以确定它。

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

What you are doing is equivalent to this

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>;

, with coupons not null and converted null.

Which means the cast is failing.
This does not solve your problem, but at least identifies it.

Perhaps you are using a different version of Entity Framework?

∝单色的世界 2024-12-28 11:41:32

获取 SQL从实体框架查询 IQueryable 帮助我解决了这个问题,以满足稍微不同的要求,我需要访问 TraceString AND 底层参数,以便我可以注入一些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();

Getting the SQL Query From an Entity Framework IQueryable helped me solve this issue to satisfy a slightly different requirement, I need to access the TraceString AND the underlying parameters so I could inject a few IQueryable<> expressions into a .SqlQuery<>()

When you inspect an IQueryable during a debug session you can see that internally it uses ObjectQuery, but it does not Inherit from ObjectQuery so you cannot cast it directly. We can however use Reflection to access the internal query object.

Here's Steve Fenton's code wrapped into an Extension Method:

    /// <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>;
    }

Now your code can look like this:

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文