Contents
Introduction
Its Friday evening, a good time to share a little something I’ve been working on.
.NET 3.0 brought with it a fantastic new language (VB, C#) extension called LINQ which stands for Language-Integrated Query.
Microsoft describes it as “a set of extensions to the .NET Framework that encompass language-integrated query, set, and transform operations. It extends C# and Visual Basic with native language syntax for queries and provides class libraries to take advantage of these capabilities.”
In short it gives the developer a more general syntax for querying sets or collections of data.
The beautiful thing about LINQ is that it can be used over any collection whether its XML, Database or even objects so long as they support the IEnumerable<T> interface.
For more information see the resources section of this article or simply google/bing it.
LINQ to Tridion In Action
Since LINQ provides a simple and powerful way to retrieve information from just about anything I thought to myself that it might be nice to have such a thing when working with Tridion.
Obviously the Tridion API is large enough and I only wanted to create a simple example but make it useful, therefore I focused on the ItemFields collections in Tridion.
Anyone who worked or played with the TOM.NET API must have quickly noticed that Tridion items such as components no longer have a Fields collection or MetadataFields collection as did the old COM API. Instead to retrieve those we need to create a new instance of the ItemFields object by passing information from the instance we want to get the fields for. In my article: Tridion Extension Methods I created an extension method that allows you to call Fields directly on a Component instance and get back an instantiated ItemFields collection.
Anyone who had the chance to work with the ItemFields and ItemField objects probably noticed that to get the actual value we need to cast the base ItemField to a more specific Derivative type (TextItemField, DateItemField, etc.).
This structure unfortunately does not work too well with LINQ queries for a few reasons, one of them being that performing a query on a Fields collection should ideally return all values and not just for a specific type. Another reason is that one ItemField may have several values (multivalued field) and that is more difficult to express in a generic query.
Ok, enough mumbling, lets get to some code:
So to get support for my LINQ to Tridion all you need is to make sure you are referencing the classes in the code I’ve made available to download, either by adding the class to your project or by referencing the assembly and add the using statement for namespace: “Tridion.ContentManager.Extensions.Linq“. Thats it.
Lets see an example:
1 2 3 4 5 6 7 8 9 10 |
var comp = session.GetObject("tcm:2-123") as Component; var q = from f in comp.Fields() where f.Name == "links" select f.ComponentValue.Title; foreach (var c in q) { Console.WriteLine("linked component title: " + c); } |
Whats this example does is first gets a component from Tridion, then we query for all values of a field named “links” that we know is of type component link. The ComponentValue returns a component instance from which we can get any component property such as its title. With the .NET ability to infer what type of results we want, in this case String, ‘q’ is now a collection (IEnumerable<String>) of titles of the components linked to our original component:
Lets now go through other parts of the code above. You may have noticed that the component instance exposes a method called ‘Fields()‘:
This is an extension method that returns a IEnumerable<LinqItemField>. The LinqItemField and the LinqItemFields classes are used to abstract all the nasty business of having the need to cast the ItemField objects to get their value. This also takes care of multivalued fields.
The default Value property returns a string value for any type of field. For a component link field the returned value will be the TCM URI of the linked component.
But LinqItemField comes with nice helper properties that can return a more specific type such as: DateValue, NumberValue and as the example shows also ComponentValue.
Currently keyword fields will return the string value of the keyword and embedded fields are not handled.
For comparison, this is how we would do the same thing when working with the API directly:
1 2 3 4 5 6 7 8 9 10 |
var comp = session.GetObject("tcm:2-123") as Component;
var compFields = new ItemFields(comp.Content, comp.Schema);
var compLink = compFields["links"] as ComponentLinkField;
foreach (var c in compLink.Values)
{
Console.WriteLine("linked component title: " + c.Title);
}
|
Which I think is less elegant than the LINQ code but perhaps that’s just me.
Here’s another example showing the coolness of Anonymous Types in .NET:
1 2 3 4 5 6 7 8 9 10 |
var comp = session.GetObject("tcm:2-123") as Component;
var q = from f in comp.Fields()
where f.Name == "contentType"
select new { Name = f.Name, Value = f.Value };
foreach (var c in q)
{
Console.WriteLine("{0}: {1}", c.Name, c.Value);
}
|
By using the keyword new and putting the properties names and their values within the curly braces, the Compiler will create a new (anonymous) type for us that will have these two properties, Name and Value. and of course VS gives us nice Intellisense support:
It was fun playing around with this and hopefully someone can use it in their implementations or at least learn from the examples I’ve provided.
This code can be integrated into modular templates code and with the next version of Tridion we should be able to use this with Event System and other types of projects as TOM.NET becomes Read/Write capable.
Source Code
Can be downloaded here.
good stuff! Will use in my next implementation for sure. thanks
Good to read interesting in-depth articles like this. Thank you!
Hi Yoavniran,
Very Nice articles,especially i liked Linq.
Planning to implement the same in my project soon.
One small information required related to tridion.
Can I load componets using javascript?
My requirement is needs to show componets randomly.
Can you help me in this regard?