in

dotnet.org.za

South African .NET Developer Portal

Reyn's Blog

Divide and Conquer !
Remember, pain is just fear leaving your body !

SharePoint query builder.

I’ve been working with Microsoft SharePoint, on and off, for about 3 months, so don’t bite me if something in that ball of yarn already does this :-)

 

If you’ve been working with SharePoint you would have come across it’s lists. Lists are like tables in a database, they have columns/records etc. These list are queried via an xml based language called CAML.

 

A typical query would look like this:

 

<Where>

<Eq>

<FieldRef Name="SomeColumn1" />

<Value Type="Text" >SomeValue1</Value>

</Eq>

</Where>

 

This would return all the records which have a value in column “SomeColumn1” equal to “SomeValue1”. Simple, isn’t it.

 

The agonizing pain only surfaces when the queries get more complex eg,

 

<Where>

<Or>

<And>

<Eq>

<FieldRef Name="SomeColumn1" />

<Value Type="Text" >SomeValue1</Value>

</Eq>

<Eq>

<FieldRef Name="SomeColumn2" />

<Value Type="Text" >SomeValue2</Value>

</Eq>

</And>

<And>

<Eq>

<FieldRef Name="SomeColumn2" />

<Value Type="Text" >SomeValue2</Value>

</Eq>

<Eq>

<FieldRef Name="SomeColumn3" />

<Value Type="Text" >SomeValue3</Value>

</Eq>

</And>

</Or>

</Where>

 

Logically it is equivalent to this:

 

((SomeColumn1 == “SomeValue1”) AND (SomeColumn2 == “SomeValue2”)) OR ((SomeColumn3 == “SomeValue2”) AND (SomeColumn3 == “SomeValue3”))

 

Clearly writing this by hand will become unmanageable very quickly, especially if you want to exclude parts of the query based on, say, if a textbox have been left blank.

 

A simple framework

 

The solution I choose works like this. All the query keywords are represented by classes and implement the IQueryInterface interface:

 

 

interface IQueryElement

{

      // The output of the element

      string Output

      {

            get;

      }

     

      // Must return true if the element is to be included

      bool Evaluate

      {

            get;

      }

}

 

 

Thus something simple like equals is then implemented like this:

 

 

class QEq : ITestOperator

{

      IQueryElement qe;

     

      // Constructor

      public QEq(IQueryElement queryElement)

      {

            qe = queryElement;

      }

           

      public string Output

      {

            get

            {

                  return "<Eq>"+qe.Output+"</Eq>";

            }

      }

 

      public bool Evaluate

      {

            get

            {

                  if (qe == null)

                        return false;

                  return qe.Evaluate;

            }

      }

}

 

 

Note that it implements ITestOperator and not IQueryElement, infact ITestOperator itself implements IQueryElement. This is just to help classify Eq as something that does a test (for equality in this case), why would we want to do this ? For compile time type checking of course, lets take a look at where this comes into play.

 

The And keyword is a bit more complex, have a look at the downloadable code.

 

 

class QAnd : IBinaryOperator, ITestOperator

      {

            public QAnd(ITestOperator _qe1,ITestOperator _qe2)

            .

            .

      }

 

 

The And operator is a binary operator, as you can see it takes two ITestOperator parameters in its constructor. If a developer tries to use anything but an ITestOperator he/she would get a compile time error.

 

Ok, that’s nice and all, but lets have a look at complete example:

 

 

// Define our tests

QEq someColumn1 = new QEq(new QFieldRefValue("SomeColumn1","SomeValue1",SPQueryTypes.Text));

                 

// Specify the combination of our tests

QQuery query = new QQuery(new QWhere(someColumn1));

                 

// Get the query

System.Console.WriteLine(query.Output);

 

Query 1

 

Yes, you guessed it, it’s the first query right at the top of this page. What’s that QFieldRefValue you ask ? Well, its:

 

 

class QFieldRefValue : IQueryElement

      {

            public QFieldRefValue(string _fieldname, string _qvalue, SPQueryTypes _type)

            .

            .

      }

 

           

The QFieldRefValue class takes a column name a value and a type at it’s constructor, this represents the column and what it will be tested against. The QEq class wraps the QFieldRefValue class to test the “SomeColumn1” column for equality against “SomeValue1” which is of type Text, an enum (Add some more, I haven’t included them all).

 

The second xml query would look like this:

 

 

// Define our tests

QEq someColumn1 = new QEq(new QFieldRefValue("SomeColumn1","SomeValue1",SPQueryTypes.Text));

QEq someColumn2 = new QEq(new QFieldRefValue("SomeColumn2","SomeValue2",SPQueryTypes.Text));

QEq someColumn3 = new QEq(new QFieldRefValue("SomeColumn3","SomeValue3",SPQueryTypes.Text));

                       

// Specify the combination of our tests

QQuery query = new QQuery(

                  new QWhere(

                        new QOr(

                              new QAnd(someColumn1,someColumn2),

                              new QAnd(someColumn2,someColumn3)

                           )));

                 

// Get the query

System.Console.WriteLine(query.Output);

 

Query 2

That’s quite a bit more maintainable.

 

An added bonus

 

I can hear you cry, “It would never stay that simple because I have a dynamic beast of a query!”, fear not, the evaluate method you saw in the IQueryElement interface has a purpose.

 

So you have a query which lets the user search on 3 columns, name, surname and hobby. The query uses ANDs like in query 2 to search for records which have all three the fields, but what happens when the name textbox is left empty ? If you decide to exclude the name for the query all you need to change (just taking the name for now) is :

 

 

// Define our tests

QEq name = new QEq(

            new QFieldRefValue("Name",

                               txtName.Text.Equals(“”)? null : txtName.Text,

                               SPQueryTypes.Text));

 

Query 3

 

This will set the value of the test to null if the textbox’s text is empty, and guess what ? The query will sort itself out. That means that you don’t have to pay special attention to the final query you build with all the composite ANDs and ORs.

 

Give the downloadable code a try(http://www.reyn.co.za/index.php?pr=SP_Query_Builder). If you find a bug, found a better way of doing this or start using this for your work/own project, drop a comment.

Published Jul 13 2004, 12:57 AM by reyn
Filed under:

Comments

 

Pieter said:

mmmmmmm

Now where have I seen this before? :D

I have to confess, reyn is saving us a bunch of time with this!
July 13, 2004 7:11 AM
 

Arno Nel said:

Ahh, another sharepoint man :)
Can you send the code to me to take a look, cant seem to find a download.
arnon
@
nvisionit
.co.za

(sorry bout mail, spam protect)
July 13, 2004 7:41 AM
 

Reyn said:

Bahha, for the record, I built something similar at work. I went home and improved on it (completely rewrote it), so my employer scores :)
July 13, 2004 8:32 AM
 

Armand du Plessis said:

yup, using it :-)
July 13, 2004 1:00 PM
 

SK said:

Great idea - would you mind sending me the code? I'd love to use it!

sk_atlanta@hotmail.com

thanks!
July 26, 2004 7:58 PM
 

Kevin said:

That looks pretty sweet, could you send me the code?

stain_07@yahoo.com

Thanks man
July 30, 2004 1:07 AM
 

Reyn said:

In the meantime I have added variable sized parameter support and a constructor which accepts an arraylist of ITestOperator to the AND and OR operators. So building cleaner, larger tests are possiblible now.
July 30, 2004 7:19 AM
 

Paul said:

EXACTLY what i need! Nice work :)

could you please send me the source code?
my e-mail adress is paul@dds.nl


thanks a lot in advance...
July 30, 2004 8:47 AM
 

Murat said:

Codeyou send me the full code for this? It's just what I need.
Murat
myorukoglu@minitab.com
August 10, 2004 10:24 PM
 

Alex said:

great code !
can you send it also to alexr@ocs.moital.gov.il ?
thanks you
August 15, 2004 3:47 PM
 

Alex said:

Thanks for the code , will use it in my work .
Only one comment : it's more likely to send array of TestOperators to BinaryOperators , because where clause can also be like this :

where ( a = 1 and b =2 and c = 3 ) or ( a = 1 and b = 3 and c = 2 ) etc.
August 16, 2004 9:43 AM
 

Reyn said:

Yes, thats why we have added a param based constructor, so that you can do: new QAnd(one,two,three,new QOr(four,five)) as well as an arraylist based one.
But I havent added that to the one I send people yet ...
August 16, 2004 12:21 PM
 

Mayur said:

Sounds Like very handy tool.
Can I ask for copy of the source code

Email address is
mayur_hirpara@hotmail.com

Thanks
August 17, 2004 6:07 PM
 

Atle Sivertsen said:

I have a list of items submitted by different people. How can I show statistics like "The Top 3 Contributors"? Also, does anyone have a search-webpart that takes list-ID as parameter? For searching a spesific list.

Thanks,
A.
September 2, 2004 9:44 AM
 

Jan Tore Lamøy said:

This looks nice!
Can I ask for a copy of the code?

jan.tore.lamoy@gmail.com
Thnx
September 3, 2004 11:01 PM
 

Gabor Lenard said:

Your code seems to be really professional. And this is exactly what I need for my list query which is based on text boses and drop down lists.

Could you send me a copy of the code? :)
My address is: sqb@lenard.hu

Thanks in advance!

Gabor
October 17, 2004 12:55 AM
 

AJ said:

I'm doing some similar work and would love to have a look at your code if you can send it on through.

Cheers,

aj@great-sky.net
October 28, 2004 7:19 PM
 

dugan said:

Would you like give me the code,Thank you very much

dugan.du@goldpac.com
October 29, 2004 4:18 AM
 

Reyn said:

I'v finally uploaded the code:
http://www.reyn.co.za/index.php?pr=SP_Query_Builder
Enjoy!
January 27, 2005 7:07 PM
 

Shaun Lineberry said:

A nice enhancement would be to add a collection to the IBinaryOperator. This would help with more dynamic queries that contain nested BinaryOperators. The builder could correctly output the structure since Sharepoint is so particular about it for nested operators.

ex.
QAnd.Add(new QAnd(someColumn1,someColumn2));
QAnd.Add(new QOr(someColumn3,someColumn4));
QAnd.Add(new QOr(someColumn5,someColumn6));


February 2, 2005 7:18 PM
 

Pete said:

I am very new at this, but I was given a project on SharePoint. The customer needs to be able to do specific queries on the lists of contacts for example. I thought I could use this query builder. I have downloaded the code, but I am not sure how to make it work with SharePoint. Could anyone give me any information on this please?
February 2, 2005 10:03 PM
 

Reyn said:

Shaun Lineberry: yup I had that in a later version, I havent had time to update this one.
Pete: For the life of me I cant remember how to tell sharepoint to evaluate the xml, I dont have access to a sharepoint system anymore (Changed from company) I'm sure google knows :)
February 3, 2005 11:13 AM
 

TrackBack said:

February 27, 2005 2:48 PM
 

TrackBack said:

February 28, 2005 11:32 AM
 

Chintu said:

Great code. Really helped me to develop a query builder. Thanks a lot.
March 19, 2005 6:55 AM
 

Noel said:

Hi,
The code is really code but u can only specify two conditions for a or or and .the class could be modified to take collections of or conditions.

Thanks

Noel
June 9, 2005 12:07 AM
 

Noel said:

Pete I am not sure if found how to work with spquery.looks like u posted to this blog some 4 months back.I am sure u did.
June 9, 2005 12:09 AM
 

Guenter said:

Great thing!
Being a developer, I changed some bist (removed the "Q" for it was annoying me to type more than needed) and use it in a little app crawling my SPS site!

Move on!

Guenter
June 10, 2005 11:21 AM
 

pepinfarb said:

Hi, have been using U2U builder but would like to give this a try.  Again, download not working.  Could you please send?  Many thanks.

steve@zioffice.com

July 29, 2006 6:53 PM
 

RajKrishnan said:

Great work. Unable to download the code. Can you send it to me?

rajkr@microsoft.com

October 20, 2006 7:31 PM
 

Gowda said:

I would be grateful if could send me the complete code.

May 8, 2007 3:01 PM
 

CarlosMag said:

Can you send me the code...?

ThankYou afterhand...

(CarlosMaggiotti@Hotmail.com)

May 8, 2007 9:18 PM
 

leonwoo said:

Please send me the code please.....

thank you.

August 7, 2007 8:24 AM
 

Cynthia said:

I am looking for something like this.  Great code.

Please send your code to cjiang@marclife.com

Thanks a lot !

April 1, 2008 9:08 PM
 

Kenny said:

Can you send me the code please to anfkenny@yahoo.com

May 20, 2008 7:45 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Powered by Community Server (Commercial Edition), by Telligent Systems