tags:

views:

529

answers:

7

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?

+2  A: 
var pagedData = aDataSource.Skip(20).Take(10);

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

Andreas Grech
+1  A: 

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

myQueryable = myQueryable.Skip(10).Take(10);
TheSoftwareJedi
+10  A: 
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);
James Curran
For your second case, it's probably easier to just use extension methods, rather than mix in the language syntax: var q = Choices.Where( x => x.SomeField == SomeValue ).Skip( (page - 1) * pageSize ).Take( pageSize );
Emperor XLII
In the first case you can delete `from X in` and `select X`.
Daniel Earwicker
+1  A: 

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"));
}
Marc Gravell
+1  A: 

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

If you're anything like me and want samples, there was talk of this not long ago over on AProgrammersJournal...

Using Linq to paginate your ObjectDataSource

invenetix
+2  A: 

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);
}
CMS
+3  A: 

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);
Kyle LeNeau