Welcome to AspAdvice Sign in | Join | Help

SharePoint CAML Queries - Grouping Clauses

I've been using CAML queries in SharePoint for some time now to fetch data that I need from lists and document libraries. For the longest time, I couldn't find the right way to group clauses together so I would often be stuck simplifying my queries and trimming out the fat in code after retrieving my data set.

For example, if i wanted to form a query like this:

 WHERE X==XValue AND (Y == YValue OR Z == ZValue)

You'd think that a CAML query like this would work:

<Where>
  <And>

    <Eq>
      <FieldRef Name="X" />
      <Value Type="Text">XValue</Value>
    </Eq>
    <Or>
      <Eq>
        <FieldRef Name="Y" />
        <Value Type="Text">YValue</Value>
      </Eq>
      <Eq>
        <FieldRef Name="Z" />
        <Value Type="Text">ZValue</Value>
      </Eq>
    </Or>
  </And>
</Where>

But this will not group the OR clause. You'd end up with "WHERE X==XValue AND Y == YValue OR Z == ZValue". In order to get the desired query results, you need to use a special attribute called "Group" on your Or clause like this:

<Where>
  <And>

    <Eq>
      <FieldRef Name="X" />
      <Value Type="Text">XValue</Value>
    </Eq>
    <Or Group="true">
      <Eq>
        <FieldRef Name="Y" />
        <Value Type="Text">YValue</Value>
      </Eq>
      <Eq>
        <FieldRef Name="Z" />
        <Value Type="Text">ZValue</Value>
      </Eq>
    </Or>
  </And>
</Where>

Sponsor
Posted by zbussinger | 0 Comments

National City Alerts LIVE

On Sunday morning, my team at National City launched the new Alerts functionality in Online Banking. The launch and preceding pilot were both great successes with only a small number of fairly negligible bugs to sort out. I've been on this project since mid June as a contractor for Brulant, Inc.

So if you have a National City account, start using alerts! You can get email alerts on up to two email addresses (primary and secondary) for all kinds of things like balances, transfers, overdrafts, account changes, and more. It's pretty cool stuff.

Sponsor
Posted by zbussinger | 0 Comments

Custom Sorting a .NET DataGrid: IComparer and DataView

The need often arises to custom sort a DataGrid when working with displaying data in a sortable manner. You may for example wish to make your grid sortable in ascending or descending order by any column. I recently had to do this, and from my research found that there are really two ways to do this (depending on your needs). The first (and preferable, IMO) method is to use the IComparer interface. To do so, let's start with this grid:

 

<asp:DataGrid ID="dgMyGrid" runat="server" BorderWidth="0" Visible="True" CellPadding="0" Width="99%" AutoGenerateColumns="False" BorderStyle="None" GridLines="None" EnableViewState="False" Title="My Grid" OnItemDataBound="dgMyGrid_ItemDataBound" AllowSorting="true" OnSortCommand="dgMyGrid_Sort">

 

<HeaderStyle CssClass="dgHeader"></HeaderStyle>

 

<Columns>

 

<asp:BoundColumn HeaderStyle-HorizontalAlign="Left" ItemStyle-HorizontalAlign="Left" HeaderText="Date" DataFormatString="{0:MM/dd/yyyy}" HeaderStyle-CssClass="dgHeader" HeaderStyle-Width="70" ItemStyle-Width="70" SortExpression="DateCreated" />

 

<asp:BoundColumn HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center" HeaderText="Account" HeaderStyle-CssClass="dgHeader" HeaderStyle-Width="100" ItemStyle-Width="100" SortExpression="AccountNumber" />

 

<asp:BoundColumn HeaderStyle-HorizontalAlign="Left" ItemStyle-HorizontalAlign="Left" HeaderText="CustomerName" HeaderStyle-CssClass="dgHeader" HeaderStyle-Width="250" ItemStyle-Width="250" SortExpression="CustomerName" />

 

</Columns>

 

</asp:DataGrid>

 

 

 

Now that we have a grid in place, we need to add an enumeration for the columns into our page. This enumeration will be used for both methods of sorting.

 

Public Enum dgMyGridColNames

 

    Date = 0

 

    Account

 

    Customer

 

End Enum

 

 

You’ll also need a couple of constants for the sort order:

 

    Public Const SORT_ORDER_ASCENDING As String = "Ascending"

 

    Public Const SORT_ORDER_DESCENDING As String = "Descending"

 

    Private Const SORT_ORDER_NONE As String = "None"

 

 

The dgMyGrid Sort method will recognize which column is clicked on and do the work that decides which column and which order we are sorting by. You’ll have to come up with your own method of keeping track of whether you’re sorting ascending or descending and by which column. In my case, used a label for each column in the grid which stored the word “ascending” or “descending” in it depending on which column the user clicks on. Here’s the general idea:

 

Protected Sub dgMyGrid_Sort(ByVal sender As Object, ByVal e As DataGridSortCommandEventArgs)

 

        Select Case e.SortExpression

 

            Case "DateCreated"

 

                Select Case lblDateCreatedSortOrder.Text

 

                    Case SORT_ORDER_ASCENDING, SORT_ORDER_NONE

 

                        lblDateCreatedSortOrder.Text = SORT_ORDER_DESCENDING

 

                        lblAccountNumberSortOrder.Text = SORT_ORDER_NONE

 

                        lblCustomerSortOrder.Text = SORT_ORDER_NONE

 

 

                        SortGrid(dgMyGridColnames.Date, SORT_ORDER_DESCENDING)

 

                    Case SORT_ORDER_DESCENDING

 

                        lblDateCreatedSortOrder.Text = SORT_ORDER_ASCENDING

 

                        lblAccountNumberSortOrder.Text = SORT_ORDER_NONE

 

                        lblCustomerSortOrder.Text = SORT_ORDER_NONE

 

 

                        SortGrid(dgMyGridColnames.Date, SORT_ORDER_ASCENDING)

 

                    Case Else

 

                End Select

 

            Case "AccountNumber"

 

                Select Case lblAccountNumberSortOrder.Text

 

                    Case SORT_ORDER_ASCENDING, SORT_ORDER_NONE

 

                        lblAccountNumberSortOrder.Text = SORT_ORDER_DESCENDING

 

                        lblDateCreatedSortOrder.Text = SORT_ORDER_NONE

 

                        lblCustomerSortOrder.Text = SORT_ORDER_NONE

 

 

                        SortGrid(dgMyGridColnames.Account, SORT_ORDER_DESCENDING)

 

                    Case SORT_ORDER_DESCENDING

 

                        lblAccountNumberSortOrder.Text = SORT_ORDER_ASCENDING

 

                        lblDateCreatedSortOrder.Text = SORT_ORDER_NONE

 

                        lblCustomerSortOrder.Text = SORT_ORDER_NONE

 

 

                        SortGrid(dgMyGridColnames.Account, SORT_ORDER_ASCENDING)

 

                    Case Else

 

                End Select

 

            Case "CustomerName"

 

                Select Case lblCustomerSortOrder.Text

 

                    Case SORT_ORDER_ASCENDING, SORT_ORDER_NONE

 

                        lblCustomerSortOrder.Text = SORT_ORDER_DESCENDING

 

                        lblDateCreatedSortOrder.Text = SORT_ORDER_NONE

 

                        lblAccountNumberSortOrder.Text = SORT_ORDER_NONE

 

 

                        SortGrid(dgMyGridColnames.colSubj, SORT_ORDER_DESCENDING)

 

                    Case SORT_ORDER_DESCENDING

 

                        lblCustomerSortOrder.Text = SORT_ORDER_ASCENDING

 

                        lblDateCreatedSortOrder.Text = SORT_ORDER_NONE

 

                        lblAccountNumberSortOrder.Text = SORT_ORDER_NONE

 

 

                        SortGrid(dgMyGridColnames.Customer, SORT_ORDER_ASCENDING)

 

                    Case Else

 

                End Select

 

            Case Else

 

        End Select

 

    End Sub

 

 

 

And here is the SortGrid method:

 

Protected Sub SortGrid(ByVal column As dgMyGridColnames, ByVal sortOrder As String)

 

       Dim arrayDS As ArrayList = GetMyDataSource()

 

Dim comparer As AlertListComparer = New AlertListComparer()

 

       comparer.ColType = column

 

       comparer.SortOrder = sortOrder

 

       arrayDS.Sort(comparer)

 

 

       dgMyGrid.DataSource = arrayDS

 

       dgMyGrid.DataBind()

 

End Sub

 

 

 

 

Finally, this is how you would implement the IComparer class (the “comparer” object declared in the previous method that gets passed into the ArrayList.Sort() function):

 

Public Class AlertListComparer

 

    Implements IComparer

 

 

    Public SortOrder As String

 

    Public ColType As MessageCenterRequestList.alertsDGColnames

 

 

    Public Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements System.Collections.IComparer.Compare

 

        Dim xDetail As <WHATEVER OBJECT TYPE IS IN YOUR ARRAYLIST DATASOURCE>

 

        Dim yDetail As <WHATEVER OBJECT TYPE IS IN YOUR ARRAYLIST DATASOURCE>

 

 

        xDetail = CType(x, <OBJECT TYPE IN YOUR ARRAYLIST DATASOURCE>)

 

        yDetail = CType(y, <OBJECT TYPE IN YOUR ARRAYLIST DATASOURCE>)

 

 

        ' Less than zero x is less than y.

 

        ' Zero x equals y.

 

        ' Greater than zero x is greater than y.

 

        Select Case ColType

 

            Case MyClass.dgMyGridColnames.Account

 

                Select Case SortOrder

 

                    Case MyClass.SORT_ORDER_ASCENDING

 

                        Return String.Compare(xDetail.AccountKey, yDetail.AccountKey)

 

                    Case MyClass.SORT_ORDER_DESCENDING

 

                        Return String.Compare(yDetail.AccountKey, xDetail.AccountKey)

 

                End Select

 

 

            Case MyClass.dgMyGridColnames.Date

 

                Select Case SortOrder

 

                    Case MyClass.SORT_ORDER_ASCENDING

 

                        Return Date.Compare(xDetail.DateCreated, yDetail.DateCreated)

 

                    Case MyClass.SORT_ORDER_DESCENDING

 

                        Return Date.Compare(yDetail.DateCreated, xDetail.DateCreated)

 

                End Select

 

 

            Case MyClass.dgMyGridColnames.Customer

 

                Select Case SortOrder

 

                    Case MyClass.SORT_ORDER_ASCENDING

 

                        Return String.Compare(xDetail.Subject, yDetail.Subject)

 

                    Case MyClass.SORT_ORDER_DESCENDING

 

                        Return String.Compare(yDetail.Subject, xDetail.Subject)

 

                End Select

 

        End Select

 

 

    End Function

 

End Class

 

 

 

The idea here is that the Object.Compare(x, y) methods will return -1 if x < y, 0 if x = y, and 1 if x > y. The class simply compares the currently indexed object in the array to the next object (x is current, y is next).

 

You can even add logic to custom handle cases where two items in the same column are equal and you want to sort by the next column. This would be done like so:

 

Select Case ColType

 

            Case MyClass.dgMyGridColnames.Account

 

                Select Case SortOrder

 

                    Case MyClass.SORT_ORDER_ASCENDING

 

If (String.Compare(xDetail.AccountKey, yDetail.AccountKey) = 0) Then

 

                       If (xDetail.Date > yDetail.Date) Then

 

                                Return -1

 

                       ElseIf (xDetail.Date < yDetail.Date) Then

 

                                Return 1

 

Else

 

                        Return String.Compare(xDetail.AccountKey, yDetail.AccountKey)

 

                    Case MyClass.SORT_ORDER_DESCENDING

 

                        Return String.Compare(yDetail.AccountKey, xDetail.AccountKey)

 

                End Select

 

 

With this logic if the AccountKeys are equal, that means we want to go ahead and sort by Date as a secondary sort order. The same logic should be implemented for descending order with the x and y elements reversed.

 

 

 

 

Another way custom sorting can be accomplished is by using a dataview:

 

Protected Sub SortGridWithDataTable(ByVal column As alertsDGColnames, ByVal sortOrder As String)

 

        'Set up the DataTable and columns

 

        Dim ds As DataSet = New DataSet("dsSort")

 

        Dim dt As DataTable = New DataTable("tblSort")

 

 

        dt.Columns.Add("Date")

 

        dt.Columns.Add("Account")

 

        dt.Columns.Add("Customer")

 

 

        'Populate the DataTable

 

        Dim array As ArrayList = GetMyDataSourceArray()

 

        For Each item As <DataType In array> In array

 

            Dim row As DataRow = dt.NewRow()

 

            row("Date") = item.Date.ToString()

 

            row("Account") = item.AccountNumber.ToString()

 

            row("Subject") = item.Subject.ToString()

 

            dt.Rows.Add(row)

 

        Next

 

 

        ds.Tables.Add(dt)

 

        Dim dv As DataView = ds.Tables("tblSort").DefaultView

 

 

        'Sort the DataTable

 

        Select Case column

 

            Case dgMyGridColnames.Account

 

                Select Case sortOrder

 

                    Case SORT_ORDER_ASCENDING

 

                        dv.Sort = "Account ASC"

 

                    Case SORT_ORDER_DESCENDING

 

                        dv.Sort = "Account DESC"

 

                End Select

 

            Case dgMyGridColnames.Date

 

                Select Case sortOrder

 

                    Case SORT_ORDER_ASCENDING

 

                        dv.Sort = "Date ASC"

 

                    Case SORT_ORDER_DESCENDING

 

                        dv.Sort = "Date DESC"

 

                End Select

 

            Case dgMyGridColnames.Customer

 

                Select Case sortOrder

 

                    Case SORT_ORDER_ASCENDING

 

                        dv.Sort = "Customer ASC"

 

                    Case SORT_ORDER_DESCENDING

 

                        dv.Sort = "Customer DESC"

 

                End Select

 

        End Select

 

 

       dgMyGrid.DataSource = dv

 

        dgMyGrid.DataBind()

 

End Sub

 

 

 

Both of these methods of custom sorting work just fine, with the former (using IComparer) being more elegant and easy to use in my opinion. Bear in mind that your datagrid’s OnItemDatabound event will need to take into account what kind of sorting method you are using for when you bind the grid to the newly sorted datasource. One nice thing about using IComparer is that your datasource (in this case an ArrayList) retains the same object type throughout because you are not converting the source to a DataView. In my case, I had a lot of custom formatting to do based on my original datasource in the OnItemDataBound event, so it was a no-brainer for me to use IComparer.

 

Hopefully this was clear enough; now go play around with it!

Sponsor
Posted by zbussinger | 0 Comments

Save internet radio!

Today when I got to work, I browsed to pandora to listen to some streaming radio just as I usually do. To my dismay, it appears that pandora and a number of other internet radio sites are observing a "Day of Silence" to make listeners aware of an important issue concerning the welfare of these services. From the Pandora main page (6/26/2007):

 


 A Day of Silence

Hi, it's Tim from Pandora,

I'm sorry to say that today Pandora, along with most Internet radio sites, is going off the air in observance of a Day Of Silence. We are doing this to bring to your attention a disastrous turn of events that threatens the existence of Pandora and all of internet radio. We need your help.

Ignoring all rationality and responding only to the lobbying of the RIAA, an arbitration committee in Washington DC has drastically increased the licensing fees Internet radio sites must pay to stream songs. Pandora's fees will triple, and are retroactive for eighteen months! Left unchanged by Congress, every day will be like today as internet radio sites start shutting down and the music dies.

A bill called the "Internet Radio Equality Act" has already been introduced in both the Senate (S. 1353) and House of Representatives (H.R. 2060) to fix the problem and save Internet radio--and Pandora--from obliteration.

I'd like to ask you to call your Congressional representatives today and ask them to become co-sponsors of the bill. It will only take a few minutes and you can find your Congresspersons and their phone numbers by entering your zip code here.

Your opinion matters to your representatives - so please take just a minute to call.

Visit www.savenetradio.org to continue following the fight to Save Internet Radio.

As always, and now more than ever, thank you for your support.


-Tim Westergren
(Pandora founder)

 


If you enjoy internet radio like I do, I'd advise you take action and help do something to stop this. It seems we are being stripped of our liberties more and more every day (or are on the verge of it), especially when concerned with the issues of free speech in entertainment.

Just as a small example of some other disturbing goings-on of late: ESRB Placing restrictions on video game trailers

Ciao,

   -Zach
 

 

SaveNetRadio.org
Sponsor
Posted by zbussinger | 0 Comments

Sound advice.

Dinosaur comics!

 

One more, for kicks... this one is good, especially since i've been looking at regular expressions a lot the last couple of days  :)

Dinosaur Comics! 

Sponsor
Posted by zbussinger | 0 Comments

Developer cheat sheets

Often I find myself forgetting the little things during my daily development tasks, as I'm sure many of you do. Things like:

 -What was that DOS command again?

- How do I format that string?

- What the HECK was that hotkey? (as I inadvertantly delete/ mess up/ obliterate all the work I've done by using improper key combinations)

    etc......

            etc.......

                        etc............

 

Well, I've found a really awesome reference on whatis.com. It's a "cheat sheet" collection of enormous proportions for developers, and computer users in general. Do yourselves a favor and bookmark this page if you have not yet found it. Looks like it's going to be a great reference for a long time!


 

Sponsor
Posted by zbussinger | 0 Comments

Celabratory (and obligatory!) first post

I've just started my new job at Brulant, and have created a new blog. My old Learning .net blog has become an old, dead dinosaur (which I've not posted on in months). This blog is meant to be a more general purpose, all around blog focused on the development of my career and the benefit of sharing and gaining knowledge. Hopefully I can keep up on this one.

More interestingly, My old boss Steven Smith of Lake Quincy Media posted this video on Surface Computing in his blog today, and I found it completely fascinating. Start saving those pennies, folks...

Back to work! 

Sponsor
Posted by zbussinger | 0 Comments