LINQ Take() returns the same results over and over

前端 未结 2 1821
隐瞒了意图╮
隐瞒了意图╮ 2021-01-24 04:40

I want to page over some records but the Take() extension from LINQ isn\'t returning the result which I expected.

public IQueryable<         


        
相关标签:
2条回答
  • 2021-01-24 05:09

    The Take method returns the first N records (N being the parameter) or all of the records if the total is less than N. To implement paging use it in conjunction with Skip, specifying how many records to skip before taking the next page of results. You may also want to supply some total ordering to ensure that the query returns results in the same order each time.

    Note: I've assumed zero-based paging.

    private const int _pageSize = 20;
    
    public IQueryable<Person> GetPersonBetweenDates(DateTime start, DateTime end, int? page)
    {
         return dbcontext.Persons
                         .Where(x => x.RegisterDate >= start && x.RegisterDate <= end)
                         .OrderBy(x => x.LastName)
                         .ThenBy(x => x.FirstName)
                         .ThenBy(x => x.Id) // using unique id to force consistent total order
                         .Skip((page ?? 0) * _pageSize)
                         .Take(_pageSize);
    }
    
    0 讨论(0)
  • 2021-01-24 05:21

    .Take returns the specified number of results on a query, and if it is the same query it will often return the same results. To resolve this, you might use a combination of .Skip and .Take, changing the number you are Skipping and Takeing each time.

    private int counter = 0;
    public IQueryable<Person> GetPersonBetweenDates(DateTime start, DateTime end)
    {
        var results = dbcontext.Persons.Where(x => x.RegisterDate >= start && x.RegisterDate <= end).Skip(counter).Take(20);
        counter += 20;
        return results;
    }
    

    Keep in mind that you will be able to call this continuously, even after there are no more records.

    Alternatively, you could cache the query (if you aren't reinstantiating the class on each use):

    private IQueryable<Person> qry = dbcontext.Persons.Where(x => x.RegisterDate >= start && x.RegisterDate <= end);
    public IQueryable<Person> GetPersonBetweenDates(DateTime start, DateTime end)
    {
        qry = qry.Skip(20);
        return qry.Take(20);
    }
    

    Nevertheless, both of these snippets may have other issues -- see tvanfosson's comments and answer.

    0 讨论(0)
提交回复
热议问题