Monday, October 13, 2014

Camlex 4.0 and Camlex.Client 2.0 are released: list joins and field projections

I have a good news for Sharepoint developers which use Camlex library in their projects: today Camlex 4.0 and Camlex.Client 2.0 with support of list joins and field projections were released. Let’s check msdn example List Joins and Projections and see how it will look like with Camlex syntax. Suppose that we have 4 lists:

  • Orders
  • Members
  • Cities
  • States

with the following left joins:

  • Orders to Members
  • Members to Cities
  • Cities to States

In order to create CAML query with list joins we need to specify value for SPQuery.Joins and SPQuery.ProjectedFields properties. Suppose that we need to create the query for all orders made by customers from London, UK. Here is how it is done using Camlex syntax:

   1: var query = new SPQuery();
   2:  
   3: query.Query = Camlex.Query().Where(x => (string)x["CustomerCity"] == "London" &&
   4:     (string)x["CustomerCityState"] == "UK").ToString();
   5:  
   6: query.Joins = Camlex.Query().Joins()
   7:     .Left(x => x["CustomerName"].ForeignList("Customers"))
   8:     .Left(x => x["CityName"].PrimaryList("Customers").ForeignList("CustomerCities"))
   9:     .Left(x => x["StateName"].PrimaryList("CustomerCities").ForeignList("CustomerCityStates"))
  10:     .ToString();
  11:  
  12: query.ProjectedFields = Camlex.Query().ProjectedFields()
  13:     .Field(x => x["CustomerCity"].List("CustomerCities").ShowField("Title"))
  14:     .Field(x => x["CustomerCityState"].List("CustomerCityStates").ShowField("Title"))
  15:     .ToString();
  16:  
  17: query.ViewFields = Camlex.Query().ViewFields(x => new[] {x["CustomerCity"],
  18:     x["CustomerCityState"]});

Here we have 4 Camlex calls for Query, Joins, ProjectedField and ViewFields properties. Let’s see what CAML is generated for each property:

Query:

   1: <Where>
   2:   <And>
   3:     <Eq>
   4:       <FieldRef Name="CustomerCity" />
   5:       <Value Type="Text">London</Value>
   6:     </Eq>
   7:     <Eq>
   8:       <FieldRef Name="CustomerCityState" />
   9:       <Value Type="Text">UK</Value>
  10:     </Eq>
  11:   </And>
  12: </Where>

Joins:

   1: <Join Type="LEFT" ListAlias="Customers">
   2:   <Eq>
   3:     <FieldRef Name="CustomerName" RefType="Id" />
   4:     <FieldRef List="Customers" Name="Id" />
   5:   </Eq>
   6: </Join>
   7: <Join Type="LEFT" ListAlias="CustomerCities">
   8:   <Eq>
   9:     <FieldRef List="Customers" Name="CityName" RefType="Id" />
  10:     <FieldRef List="CustomerCities" Name="Id" />
  11:   </Eq>
  12: </Join>
  13: <Join Type="LEFT" ListAlias="CustomerCityStates">
  14:   <Eq>
  15:     <FieldRef List="CustomerCities" Name="StateName" RefType="Id" />
  16:     <FieldRef List="CustomerCityStates" Name="Id" />
  17:   </Eq>
  18: </Join>

ProjectedFields:

   1: <Field Name="CustomerCity" Type="Lookup" List="CustomerCities" ShowField="Title" />
   2: <Field Name="CustomerCityState" Type="Lookup" List="CustomerCityStates" ShowField="Title" />

ViewFields:

   1: <FieldRef Name="CustomerCity" />
   2: <FieldRef Name="CustomerCityState" />

As you can see joins syntax is quite straightforward:

   1: Joins().Left(x => x[...].ForeignList(...))
   2: // or
   3: Joins().Left(x => x[...].PrimaryList(...).ForeignList(...))

First syntax (without specifying primary list) is used when primary list if the same list against which query is made, second – when it is different list. For projected fields syntax is also self descriptive:

   1: .Field(x => x[...].List(...).ShowField(...))

i.e. you need to specify values for attributes of the resulting Field element.

For joins and projected fields only fluent interfaces were used for supporting multiple elements (.Join().Join()… or .Field().Field()…), i.e. there are no appropriate methods which receive collection of parameters which can be passed in order to get multiple Join or Field elements in resulting CAML. Such methods simplify dynamic creation of the parameters in runtime when their amount is not known in compile time. This approach is used in Camlex for Where and ViewFields, but I hardly may imagine scenarios when dynamic creation of join chains will be needed. If someone will need it, I will think about adding it to the library, but meanwhile only fluent interfaces for joins and projected fields will be used.

Reverse version of new features (which allows to make conversion in opposite direction from CAML to C#) is not implemented yet. It will take some time to implement it and I decided to release it later. Practically it means that e.g. if you will try to convert Joins or ProjectedFields from CAML to C# Camlex syntax on online service http://camlex-online.org (this service was launched in order to simplify Sharepoint developers which are not familiar with Camlex starting using it), it won’t work currently. But I’m going to implement it in next release so it will work after that.

If you will have any comments or feature requests please post them to discussions section of the Camlex project site.

4 comments:

  1. Nice post.
    Can you please list down the examples for Sharepoint Client version specific for Joins
    I have looked for the same all over but not able to find it, there is no defined document for this

    ReplyDelete
  2. Nikhil, in CamlQuery class there is no separate properties for joins and projected fields like in SPQuery. I.e. you should put appropriate xml tags to its ViewXml property together with Query
    query =
    View
    Query
    /Query
    Joins
    /Joins
    ProjectedFields
    /ProjectedFields
    /View
    See test_THAT_query_with_where_and_join_IS_created_successfully() unit test in client branch of Camlex sources: http://camlex.codeplex.com/SourceControl/latest.

    ReplyDelete
  3. We are using, client dll with version 15, and which is not compatible with 14 which is for Camlex, can you upgrade it or is there any other way around

    ReplyDelete
  4. Nikhil, add assembly binding redirection to your app/web.config like shown here: http://sadomovalex.blogspot.com/2011/09/assembly-binding-redirect-in-sharepoint.html (instead of 14.0.0.0 you will need to use 15.0.0.0 as target version).

    ReplyDelete