IQueryable<T> gives different result than a List<T>

独自空忆成欢 提交于 2020-07-15 10:16:21

问题


If I use Select on IQueryable on my entity framework result I'll get 4 items as a result.

If I use Select on an IQueryable.ToList() I get all 36 items.

Here's code of the function:

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

Out of the 36 items 2 Subreddits will be distinct. But since only 4 out of 36 are fetched from Select() it only finds 1 distinct.

So is there anything I can do with the LINQ expressions to get correct data so the distinct statement works or do I have to make it into a List before continuing with the Select & Distinct functions?

Edit:
by moving the where satement from the end to the start of the whole query. It appears to work correctly now. Select returns all 36 items e.t.c... which in turn makes the Distinct work since it can find more than 1 unique value.

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

回答1:


Most likely your Where clause is behaving differently in SQL Server than it would in .NET. Specifically, depending on your collation settings and such, it's likely that various .Domain values differ only by capitalization or something like that, making them "equal" to Gfycat in SQL, but not in C#.

You can capture the .ToString() on your IQueryable<> to see what SQL is being produced and try it yourself.

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



回答2:


It's difficult to be certain without source data, but Distinct works differently when pushed to the SQL.

A SQL DISTINCT query will pull records where all values are distinct. When you do a Distinct call on a list of objects in memory, by default it will use instance equality. So you may get back "duplicate" objects (objects where all field values are the same), but they will be distinct "instances", so Distinct treats them as different objects.

So it depends on what you want - do you want all Subreddit values including duplicates or do you want distinct values?

To answer your question - if you don't want the Distinct call passed down to the SQL you can call AsEnumerable() instead of ToList, which makes all further Linq queries Linq-to-Objects (IEnumerable<T>) queries instead of Linq-to-{whatever} (IQueryable<T>) queries, without the overhead of putting the items in a list.



来源:https://stackoverflow.com/questions/30313828/iqueryablet-gives-different-result-than-a-listt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!