Querying for pages

Topics: Writing modules
Jul 7, 2011 at 6:24 PM

I'm working on a module where I need to query the database for all the pages in the site.  I've used some other code for a similar module that queried content that was tagged with a specified tag:

private readonly IContentManager _cms;
IEnumerable<TagsPart> parts =
                                                .Where(tpr => tpr.Tags.Any(t => t.TagRecord.TagName == part.TagName))
                                                .Where(cpr => cpr.Id != currentItemId)
                                                .OrderByDescending(cpr => cpr.PublishedUtc)
var list = shapeHelper.List();
list.AddRange(parts.Select(p => _cms.BuildDisplay(p, "RelatedSummary")));

I thought I'd be able to use this as a starting point, but after looking back on it, I don't quite understand what's going on...in the above snippet, where does the actual page content come into play? When the BuildDisplay happens, it must be able to build a page url from the TagsPart object?

How would I modify this to have it spit out the page elements for a site?


Jul 7, 2011 at 6:46 PM

A content type is an aggregation of content parts. The TagsPart type here is just one part. The person who wrote that query was explicitly interested in that part (see the where condition that restricts the result set to items that have a specific tag). A query that gets all the content items could be just something like _cms.Query<CommonPart, CommonPartRecord>(). Now to get the URL, you would cast to the Route part: item.As<RoutePart>().Path. To get the page body, you would do item.As<BodyPart>().Text.

Jul 7, 2011 at 7:55 PM

I already had an idea that I'd just use CommonPart and that TagPart was only in that query to filter by tag name...I just wasn't sure that CommonPart gave me everything that I needed.  The extra casting stuff you provided will give me something to start off of.  I'll give this a go...

Jul 7, 2011 at 8:01 PM

This code:

IEnumerable<CommonPart> parts =_cms.Query<CommonPartCommonPart>();

Gives me a compile error:

The type 'Orchard.Core.Common.Models.CommonPart' must be convertible to 'Orchard.ContentManagement.ContentPart<Orchard.Core.Common.MOdels.CommonPart>' in order to use it as a parameter 'TPart' in the generic method 'IContentQuery<TPart,TRecord> Orchard.ContentManagement.ContentQueryExtensions.Query<TPart,TRecord>(This.IContentManager)'

Jul 7, 2011 at 8:33 PM

It would help if I looked at my code a little closer :)

IEnumerable<CommonPart> parts =_cms.Query<CommonPartCommonPart>();

Should be

IEnumerable<CommonPart> parts =_cms.Query<CommonPartCommonPartRecord>();

Back to testing out your suggestion :)

Jul 8, 2011 at 1:51 PM

My query is as follows:

IEnumerable<CommonPart> parts = _cms.Query<CommonPartCommonPartRecord>().List();

I'm having a little trouble getting the where/order by clauses working...I was hoping to be able to do something like:

IEnumerable<CommonPart> parts = _cms.Query<CommonPartCommonPartRecord>().Where(c => c.As<RoutePart>() != null).List();

The same concept for the order by OrderBy(c => c.As<RoutePart>().Path).

I don't get the casting "As" functionality when I do this...is there another way to work with the casted objects inside of the query?

Jul 8, 2011 at 5:44 PM

You can't do "as" in the where clause because that's a method of the part and where is acting on the record.

Jul 8, 2011 at 5:46 PM

You will need to Join first with the RoutePartRecord so that you can write a meaningful query.

Jul 8, 2011 at 5:48 PM

Yeah, that makes sense, thanks.

Jul 12, 2011 at 10:02 PM

I'm back to trying to figure this query out and I'm still getting stuck...I'm looking to write a query that does the following:

select route.title, route.path from content types where type = page order by route.path

I started with something like:

var rp = _cms.Query<CommonPartCommonPartRecord>()

Though, I'm not sure if this is the right direction...I'm so used to writing plain SQL...can you point me to an example or assist me with how this query might look in the context of Orchard?

Jul 13, 2011 at 10:16 PM

I don't think you need the Join unless you want to use the route part record for the query (like a where clause). Your query should be something like this:

_cms.Query(VersionOptions.Published, "Page").Slice(10)

Jul 14, 2011 at 2:28 PM

I used:

var result = _cms.Query(VersionOptions.Published, "Page").List());

And that compiled just fine...that being said, I think I need the join because I need it to be ordered by RoutePart's path property

Jul 14, 2011 at 2:38 PM

Looking at some Orchard source, I found and was able to use this:

var pages = _cms.Query(VersionOptions.Published, "Page")
                                .OrderBy<RoutePartRecord,string>(record => record.Path)

So just for learning purposes, let's assume I needed the join, maybe I needed to only include pages where routepart paths contain "ninja" in the path...can you elaborate on how that join would work?

Jul 14, 2011 at 6:19 PM
Edited Jul 14, 2011 at 6:23 PM

Well it would simply be a case of adding a where clause:

var pages = _cms.Query(VersionOptions.Published, "Page")
                .Where(record => record.As<RoutePart>().Path.Contains("ninja"))
                .OrderBy(record => record.Path)

Jul 18, 2011 at 1:18 PM

Thanks, that would work...I was actually looking more for the join syntax, but thank you for your reply...