14

Is it possible to using "paging" functionality in Linq queries? Let's say I have some XML like this:

<Root>
    <BetaSection>
        <Choices>
            <SetA>
                <Choice id="choice1">Choice One</Choice> 
                <Choice id="choice2">Choice Two</Choice>
                <Choice id="choice3">Choice Three</Choice>
                .
                .
                .
                <Choice id="choice48">Choice Forty-Eight</Choice>
                <Choice id="choice49">Choice Forty-Nine</Choice>
                <Choice id="choice50">Choice Fifty</Choice>
            </SetA>
        </Choices>
    </BetaSection>
</Root>

If I wanted to implement paging functionality, would I be able to provide an offset to a LINQ query such that I could start at the 11th element and end on the 20th element? If so, would the query be any different if the data was a list of objects instead of XML?

4

7 回答 7

20
var q = from X in Choices.Skip((page-1)*pageSize).Take(pageSize)
        select X;

Now, if you need a where clause in it, it gets a bit trickier:

var q = (from X in Choices
         where x.SomeField == SomeValue
         select X).Skip((page-1)*pageSize).Take(pageSize);
于 2008-12-08T20:46:58.690 回答
3

Absolutely - Skip() and Take() achieve paging, and are supported by pretty-much all LINQ providers.

In this case it looks like you are using LINQ-to-Xml, so feel free to ignore the following bit - but for general info: note that if the data is coming from a database via a stored procedure, it is hard to page at the server. You can, however, compose (i.e. page) "UDF"s. LINQ-to-SQL supports UDFs (via [FunctionAttribute]), but not Entity Framework. If you are using auto-generated database queries this isn't an issue.

Note that with xml, you could also do a lot with xpath - here using XmlDocument:

foreach (XmlElement el in doc.SelectNodes(
  "/Root/BetaSection/Choices/SetA/Choice[position() > 11 and position() < 20]"))
{
    Console.WriteLine(el.GetAttribute("id"));
}

or with Skip()/Take() (still with XmlDocument):

foreach (var el in doc.SelectNodes(
  "/Root/BetaSection/Choices/SetA/Choice").Cast<XmlElement>()
  .Skip(10).Take(10))
{
    Console.WriteLine(el.GetAttribute("id"));
}
于 2008-12-08T20:47:15.240 回答
3

Take a look to the Queryable.Skip and Queryable.Take methods.

Also see this useful extension methods for paging,

with that methods you can do this like this:

List<string> names = new List<string>();
names.AddRange(new string[]{"John","Frank","Jeff","George","Bob","Grant", "McLovin"});

foreach (string name in names.Page(2, 2))
{
    Console.WriteLine(name);
}
于 2008-12-08T20:47:26.893 回答
3

James Curran has it right, you can simplify that by creating an extension method for reuse later on.

You could also modify the code to return you an object that can track how many items total are in the list and how many pages there should be based on the pageSize and pageIndex.

public static IQueryable<T> ToPageOfList<T>(this IQueryable<T> source, int pageIndex, int pageSize)
{
    return source.Skip(pageIndex * pageSize).Take(pageSize);
}

//Example
var g = (from x in choices select x).ToPageOfList(1, 20);
于 2008-12-08T21:01:29.080 回答
2
var pagedData = aDataSource.Skip(20).Take(10);

That way, you are skipping 20 elements and taking the next 10

于 2008-12-08T20:46:04.510 回答
1

The "Take" and "Skip" extension methods provide for this.

myQueryable = myQueryable.Skip(10).Take(10);
于 2008-12-08T20:46:54.430 回答
1

Yes it is. You'd have to get the XML into a proper DataSource format and then this thread over on the MSDN forums should provide the necessary steps to give you the ability on how to implement it...

MSDN - LINQ with pagination

于 2008-12-08T20:47:26.007 回答