【问题标题】:How can I convert IQueryable<T> to ObjectQuery<T>?如何将 IQueryable<T> 转换为 ObjectQuery<T>?
【发布时间】:2012-01-22 01:55:14
【问题描述】:

我正在尝试应用这篇文章中的建议:Tip 22 - How to make Include really 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>;

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

知道我做错了什么吗?

【问题讨论】:

  • 如果您使用var 而不是IEnumerable&lt;Coupon&gt; 会怎样? IQueryable&lt;T&gt;IEnumerable&lt;T&gt; 不是一回事。
  • 你的 ctx 是 DbContext 还是 ObjectContext? ObjectQuerys 仅与 ObjectContexts 一起使用。您还可以在调试器中检查 coupons.GetType(),以查看查询的真正类型。
  • 谢谢。我更新了帖子说我正在使用 DBContext。
  • 在这种情况下,唯一的答案可能是“您不能将 IQueryable&lt;T&gt; 转换为 ObjectQuery&lt;T&gt;,除非 IQueryable&lt;T&gt; 确实是 ObjectQuery&lt;T&gt;。”不过,我想知道为什么你真的需要它。在您的查询中,您首先不需要解决方法,但如果您这样做了,假设您是 using System.Data.Entity;(from x in ctx.Coupons ... select x).Include(...) 是否不能解决问题?
  • @Hvd。谢谢。我在 using 声明中没有 System.Data.Entity 并且依靠 Intellisense 来确定允许的内容 - 所以我认为我不能使用 .Include !然后开始阅读一篇“证实”这种误解的旧博客文章。嗬!我猜不应该在疲倦和沮丧时编码。如果您想发布答案,我会接受它 - 或者我会在几天后自行回答,参考您的评论。

标签: c# .net iqueryable eager-loading objectquery


【解决方案1】:

你所做的就相当于这个

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 为空。

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

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

【讨论】:

  • 谢谢。确实可能这种解决方法不再适用,因为该帖子是在 2009 年发布的。
【解决方案2】:

从 cmets 到答案:

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

【讨论】:

    【解决方案3】:

    Getting the SQL Query From an Entity Framework IQueryable 帮助我解决了这个问题以满足稍微不同的要求,我需要访问 TraceString AND 底层参数,以便我可以将一些 IQueryable&lt;&gt; 表达式注入到 .SqlQuery&lt;&gt;()

    当您在调试会话期间检查 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();
    

    【讨论】:

      猜你喜欢
      • 2011-06-13
      • 2010-11-18
      • 1970-01-01
      • 1970-01-01
      • 2010-09-11
      • 1970-01-01
      • 2012-11-15
      • 2011-07-28
      • 1970-01-01
      相关资源
      最近更新 更多