【问题标题】:IQueryable<T> gives different result than a List<T>IQueryable<T> 给出的结果与 List<T> 不同
【发布时间】:2015-07-30 14:02:11
【问题描述】:

如果我在我的实体框架结果中对 IQueryable 使用 Select,我将得到 4 个项目。

如果我在 IQueryable.ToList() 上使用 Select,我会得到所有 36 个项目。

函数代码如下:

public ImagesGetModelView Get(int start, int count)
{
    if (count <= 0) count = 9;
    else if (count > ImageHandler.MaxResult) count = ImageHandler.MaxResult;    

        IQueryable<Image> imagesList = ImagesHandler.FetchRangeScore(start, count)
           .Where(m => m.Domain == Database.Enums.ImageDomain.Gfycat);

        //Works using list :(
        //var list = imagesList.ToList();

        //Select all subreddits once
        //Returns 4 instead of 36 if not using the list ...
        //Returns 1 instead of 2 with Distinct() if not using the list
        IEnumerable<Subreddit> subreddits = imagesList
           .Select(m => m.Subreddit); //.Distinct();           

        ImagesGetModelView result = new ImagesGetModelView()
        {
            Items = imagesList,
            Subreddits = subreddits
        };

        return result;
    } 

public IQueryable<Image> FetchRangeScore(int a_start, int a_count)
    {
        return Repository.AllQueryable().OrderByDescending(m => m.Score)
          .Skip(a_start).Take(a_count);
    }

在 36 个项目中,2 个 Subreddits 将是不同的。但是由于从 Select() 中只获取了 36 个中的 4 个,因此它只能找到 1 个不同的。

那么我可以用 LINQ 表达式做些什么来获取正确的数据,以便 distinct 语句起作用,还是我必须在继续使用 Select 和 Distinct 函数之前将其放入 List 中?

编辑:
通过将 where 语句从末尾移动到整个查询的开头。 它现在似乎可以正常工作。 Select 返回所有 36 个项目等...这反过来又使 Distinct 工作,因为它可以找到超过 1 个唯一值。

 public IQueryable<Image> FetchRangeScore(int a_start, int a_count)
    {
        return Repository.AllQueryable()
          .Where(m => m.Domain == Database.Enums.ImageDomain.Gfycat)
          .OrderByDescending(m => m.Score)
          .Skip(a_start).Take(a_count);
    }

【问题讨论】:

  • 一些模拟数据可能有助于说明您的观点。
  • 我建议您放置单独版本的逻辑(或您更改的第二个代码 sn-p)。在需要变化的代码中跟踪 cmets 可能很困难(例如,我无法判断您的示例是否损坏或正常工作)。
  • 在调用 distinct 之前进行分页是否有原因?我通常会期望相反的顺序。

标签: c# linq entity-framework


【解决方案1】:

没有源数据很难确定,但Distinct 在推送到 SQL 时会有所不同。

SQL DISTINCT 查询将提取所有值都不同的记录。当您对内存中的对象列表执行Distinct 调用时,默认情况下它将使用 instance 相等性。因此,您可能会返回“重复”对象(所有字段值都相同的对象),但它们将是不同的“实例”,因此Distinct 将它们视为不同的对象。

所以这取决于您想要什么 - 您想要所有 Subreddit包括重复项,还是想要不同的

回答您的问题 - 如果您不希望将 Distinct 调用传递给 SQL,您可以调用 AsEnumerable() 而不是 ToList,这使得所有进一步的 Linq 查询 Linq-to-Objects (@987654329 @) 查询而不是 Linq-to-{whatever} (IQueryable&lt;T&gt;) 查询,没有将项目放入列表的开销。

【讨论】:

  • 我只想要不同的值没有重复。我需要将 subreddits 明显分开以获得结果。
【解决方案2】:

很可能您的Where 子句在 SQL Server 中的行为与在 .NET 中的行为不同。具体来说,根据您的排序规则设置等,各种.Domain 值可能仅在大小写或类似方面有所不同,这使得它们在 SQL 中与 Gfycat“相等”,但在 C# 中则不然。

您可以在IQueryable&lt;&gt; 上捕获.ToString() 以查看正在生成的SQL 并自己尝试。

IQueryable<Image> imagesList = ImagesHandler.FetchRangeScore(start, count)
   .Where(m => m.Domain == Database.Enums.ImageDomain.Gfycat);
Debug.WriteLine(imagesList.ToString());

【讨论】:

  • 我相信你是对的。你让我意识到我在那里有一个 where 声明:) 我很久以前添加它进行测试并且对它视而不见。当您查看它时,它的位置非常好,但是数据集是 36 个类型中的 35 个子版块,所以直到昨晚我才注意到它是错误的。当我将它移到查询的开头时,我注意到 Debug.WriteLine() 不再返回子查询,而且一切似乎都正常。
猜你喜欢
  • 2011-10-09
  • 2013-09-03
  • 2019-11-21
  • 2010-11-18
  • 1970-01-01
  • 2020-09-12
  • 1970-01-01
相关资源
最近更新 更多