Quering list Items in the current List

Topics: Writing modules
May 10, 2011 at 4:10 PM
Edited May 10, 2011 at 4:11 PM

Hi there!

My goal is to write a part that represents a Filter Form for quering list item in the current list.

My major problem is not knowing how to interact to the current list...


First i create a list with items

List News:

      New 1

      New 2

      New 3


Then i associate a filter form that have the possibility to query by taxonomie terms.

So when i click filter button i have a controller action for quering contantmanager.contentItems, and retrive to the current "List News" the results...

I'm trying my best but i cannot understand how to do this...

Could you help me?


May 13, 2011 at 8:52 AM
Edited May 13, 2011 at 8:54 AM

I manage somehow to get this done, unfortunately i have to do it in core because i dont know how to replace Core/Containers/Controllers/ItemController, i've tried to create a module to do that but it didn't work :\

Anyway now i have another problem.


So i create another Action Result in Core/Containers/Controllers/ItemController that recive from querystring my parameter that i will use in query like this:

[HttpGet, Themed, ValidateInput(false)]
        public ActionResult Display(string path, PagerParameters pagerParameters, string text = "", string term = "")


IContentQuery<ContentItem> query = _contentManager
                .Join<CommonPartRecord>().Where(cr => cr.Container.Id == container.Id)
                .Join<RoutePartRecord>().Where(title => title.Title.Contains(text));


As you can see i search for the passing text in the title... but i want to be able to search in "orch_Orchard_Framework_ContentItemRecord" table because "Data" colum is the only place i find the fields information that i need

Data Colum:

"<Data><Evento><ImagemListagem>/Media/Default/Evento/ImagemListagem/valor4-thumb-1.gif</ImagemListagem><ImagemDetalhe></ImagemDetalhe><Tema></Tema><Resumo>&lt;p&gt;as dasd&lt;/p&gt;</Resumo><Texto>&lt;p&gt;&amp;nbsp;asdas&lt;/p&gt;</Texto><Data>01/04/2011 00:00:00</Data><SubTitulo>asd</SubTitulo><Localidade>123</Localidade><Links></Links><DataFim></DataFim></Evento></Data>"


But when i do this:

.Join<ContentItemRecord>().Where(stext => stext.Data.Contains(Text));

He throw me an exeption that ContentPartRecord is need it.


I'm in a loop here... is there another way to search in value of fields associated with that contentitem?


Please... i need this for today... :S

May 13, 2011 at 9:44 AM

Why not use the Search module API?

May 13, 2011 at 10:13 AM

i dont understand what you'r sugesting...

Search API is for a global search using Storage as a datasource...

What i want is a local search in that container for content item that have the passing text in title or associated fields and i want so search for taxonomies too.

Can you give me a good example how to use Search API for this?



May 13, 2011 at 10:45 AM

The Search module uses "ISearchBuilder" which you could use to construct your own custom search.

Don't know if it'd do everything you're after tho.

Exactly *which* fields out of Data are you looking for? Presumably they come from some actual contentpart or another?

Just a word of warning, a query like .Where(title => title.Title.Contains(text)) will be extremely slow with a large content database, which is why you should look at indexing the fields you're after instead of trying to write your own search :)

May 13, 2011 at 10:55 AM

Exactly *which* fields out of Data are you looking for? Presumably they come from some actual contentpart or another?

The fields are htmlfield, textfield, datafield an others all associated with Content Type included in that list.

May 13, 2011 at 11:36 AM

AFAIK, you can't query on custom fields. But you CAN include them in Search indexing.

If you want to use a normal content query on fields, you'll need to build a part instead.

May 13, 2011 at 5:19 PM

Doesn't the Taxonomies module already do what you need?

May 16, 2011 at 9:32 AM

bestrandleroy Taxonomies have a part record, and yes for taxonomies i can search it, but other fields dont have a part...

May 16, 2011 at 11:33 AM

Presuming i dont have any other chance to get this done...

Using search index what i'm i doing wrong here?

IContentQuery<ContentItem> query = null;

query = _contentManager.Query(VersionOptions.Published);

/* Fields */
if (!string.IsNullOrEmpty(text))
       var searchFields = Services.WorkContext.CurrentSite.As<SearchSettingsPart>().SearchedFields;
       var searchBuilder = ListQuery().Parse(searchFields, text);
       var searchResults = searchBuilder.Search();
       query = query.Join<CommonPartRecord>().Where(cr => cr.Container.Id == container.Id).Where(u => u.ContentItemRecord.Id.ToString().Contains(searchResults.Select(iId => iId.ContentItemId).ToList().ToString()));
       query = query.Join<RoutePartRecord>().Where(title => title.Title.Contains(text));
        query = query.Join<CommonPartRecord>().Where(cr => cr.Container.Id == container.Id);


It give me this exeption:

Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

May 16, 2011 at 11:45 AM

Which line gives that error?

To be honest now I understand your requirements better, you probably just want to create a ContentPart for the fields you are handling and use ContentQuery, not search.

May 16, 2011 at 12:54 PM

It's too late to create the content parts for the fields i'm using. My project is allready online with contents.

What i'm tryng to do now is to join the results of content query and search query.

And actually updating the last block of code:


IContentQuery<ContentItem> query = null;

            query = _contentManager

            /* Fields */
            if (!string.IsNullOrEmpty(text))
                var searchFields = Services.WorkContext.CurrentSite.As<SearchSettingsPart>().SearchedFields;

                var searchBuilder = ListQuery().Parse(searchFields, text);

                var searchResults = searchBuilder.Search().Select(iID => iID.ContentItemId);

                query = query.Join<CommonPartRecord>().Where(cr => cr.Container.Id == container.Id).Where(u => searchResults.Contains(u.ContentItemRecord.Id));
                query = query.Join<RoutePartRecord>().Where(title => title.Title.Contains(text));
                query = query.Join<CommonPartRecord>().Where(cr => cr.Container.Id == container.Id);


The error is this one:

Expression argument must be of type ICollection.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: Expression argument must be of type ICollection.

Source Error:


An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:

[InvalidOperationException: Expression argument must be of type ICollection.]
   NHibernate.Linq.Visitors.WhereArgumentsVisitor.GetCollectionContainsCriteria(Expression list, Expression containedExpr) +279
   NHibernate.Linq.Visitors.WhereArgumentsVisitor.VisitMethodCall(MethodCallExpression expr) +648
   NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp) +456
   NHibernate.Linq.Visitors.ExpressionVisitor.VisitLambda(LambdaExpression lambda) +32
   NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp) +504
   NHibernate.Linq.Visitors.WhereArgumentsVisitor.VisitUnary(UnaryExpression expr) +53
   NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp) +129
   NHibernate.Linq.Visitors.RootVisitor.HandleWhereCall(MethodCallExpression call) +113
   NHibernate.Linq.Visitors.RootVisitor.VisitMethodCall(MethodCallExpression expr) +987
   NHibernate.Linq.Visitors.ExpressionVisitor.Visit(Expression exp) +456
   NHibernate.Linq.Visitors.NHibernateQueryTranslator.TranslateInternal(Expression expression) +99
   Orchard.ContentManagement.DefaultContentQuery.Where(Expression`1 predicate) in d:\TeamCity\Projects\Orchard-Default\src\Orchard\ContentManagement\DefaultContentQuery.cs:86
   Orchard.ContentManagement.ContentQuery`2.Orchard.ContentManagement.IContentQuery<T,TR>.Where(Expression`1 predicate) in d:\TeamCity\Projects\Orchard-Default\src\Orchard\ContentManagement\DefaultContentQuery.cs:231
   Orchard.Core.Containers.Controllers.ItemController.Display(String path, PagerParameters pagerParameters, String text, String term) +3896
   lambda_method(Closure , ControllerBase , Object[] ) +258


This is very important to me so i can close the project...
I'm trying to find a way to go around the obvious solution, because i allready notice that for search in those fields i have do had a part of them, but in this cenario i cant!

So... in content query  provider is there a way that i can acess the Colum "Data", because is there where are all the values i need...

Or just as i'm doing join content query with search query.


Thank You!

May 16, 2011 at 2:24 PM

I'm still no wiser as to which line is failing in that code. Can you step through with the debugger and see what's actually erroring?

May 16, 2011 at 2:26 PM

Oh wait - I think I see, you just need to ToList() on the search results.

The problem with doing it this way is you are losing the entire benefit of DB queries. i.e. you're pulling out search results, and then querying them in memory.

You really should just build a Part so your fields are properly queryable. Write a migration to copy the existing field data into the parts.

May 16, 2011 at 6:31 PM

I wasn't suggesting you do as Taxonomies do, I was wondering why you weren't using Taxonomies.

Fields cannot be queried (except if like Taxonomies they take over their own storage). If something needs to be queried on, it should be a property on a part.

May 18, 2011 at 10:21 PM

Thank you all for your help.

I was able to get this done by using a ADO.NET connection retrieving ContentItemPart Data out of the table.

After getting the column Data i create a XDocument with linq for individual field value selector.

Now my part is able to submit a string parameter that can be searched on all the fields foreach Content Item.


But... here is a tricky one...

In my part i need to have a dropdownlist for Taxonomie Terms in use by the Content Items IN THAT LIST.

So far i was only able to get them all ( all all... )

Is there a way that my part (that are in Content Type "List") can get the Taxonomie ID from terms in use by Content Items of that list, so that with

Taxonomie ID i can retrieve all the terms for that Taxonomie ID?


I know it's confusing... :)


Thanks again! 

May 18, 2011 at 10:24 PM

Ouch, this sounds very wrong, sorry. You should never have to use an ADO.NET connection to read the data. You should be using a query on the content manager.

May 18, 2011 at 10:57 PM
Edited May 18, 2011 at 11:46 PM

Yeah with parts right? i got that... but as i said before i'm using fields... so...

I understant the point you are defending, really i do!

But for now... while Orchard is not able to quering on fields with content manager, fields make no sense to me.

Why use fields when they cannot be queriable by content manager? Html Field, DataTime Field, Text Field? I have to create a part for each? That really makes no sense!

If Fields are connected to Content Type, content manager HAVE to be able to querie them.

But he cant... can he?

So i got no other option... sorry


So with taxonimie problem do you got some ideia? using Content Manager this time :)