Data types using C#

Introduction

A big part of C1 CMS is the data services - C1 CMS uses LINQ as the primary interface to query data, and all data is 100% based on CLR types. Thus .NET types (interfaces) play a big role when querying and working with data in C1 CMS.

The data layer in C1 CMS totally abstracts the underlying stores like SQL Server or XML files away from the developer without sacrificing developer control. Instead of writing SQL statements or XML queries to get data, you write LINQ statements.

All data items have one common interface they all inherit from: Composite.Data.IData. In C1 CMS’s terminology an IData is what database developers would call a “table” or “schema” – an interface that inherits from IData is a definition of a data object which holds properties (name, type) and meta data like primary keys, foreign keys etc.

You can write a LINQ query without caring about the underlying store. If the underlying store is a SQL Server, then the LINQ query will be translated into a perfectly optimized SQL statement that gets the job done. And the same query, without any rewriting or even recompiling, can be used if the underlying store is XML – or any other kind of store for that matter.

Below is an example of a query that works for any data store (SQL, XML, …)

using (DataConnection connection = new DataConnection())
{
var q = 
    from page in connection.Get<IPage>()
    where page.Title == "My Title"
    orderby page.UrlTitle
    select page;
}

Here is another example that will result in an inner join statement in the SQL database and in-memory object join when XML is used.

using (DataConnection connection = new DataConnection())
{
var q = 
    from page in connection.Get<IPage>()
    from pagetype in connection.Get<IPageType>()
    where page.PageTypeId == pagetype.Id
    orderby page.Title
    select new { page.Title, pagetype.Name };
}

The last example shows a query that will result in a left outer join in the SQL database and in-memory object join when XML is used.

using (DataConnection connection = new DataConnection())
{
var q = 
    from pagetype in connection.Get<IPageType>()
    join page in connection.Get<IPage>() on pagetype.Id equals page.PageTypeId into sub
    from s in sub.DefaultIfEmpty()
    select s;
}

In all these examples IPage and IPageType are data interfaces that inherit from the base data interface IData. Below is a minimal example of a data type in C1 CMS:

[KeyPropertyName("Id")]
[DataScope(DataScopeIdentifier.PublicName)]
[ImmutableTypeId("{87122C34-E622-4e97-BD36-CBC398B862F9}")]
public interface IPerson : IData
{
    [StoreFieldType(PhysicalStoreFieldType.Guid)]
    [ImmutableFieldId("{172DD44C-426B-4812-834B-6B45366E78CB}")]
    Guid Id { get; set; }
    [StoreFieldType(PhysicalStoreFieldType.String, 249)]
    [ImmutableFieldId("{ADB24D3D-FA2A-496a-BBE9-91CFEB88336F}")]
    string Name { get; set; }
}

As seen in this example, the class and field attributes are heavily used. C1 CMS uses these attributes as meta-information about the data type – much like you have more information about SQL tables than just the table name and column name / type. This information is used throughout the system, from the low-level data store to the UI and is the basis of data types in C1 CMS.

Please note that these custom data interfaces must be defined in a Class Library project, built as an assembly (DLL) and placed in /Bin. You cannot create them in /App_Code.

If you were to create a new Data Type using the Data type wizards in the C1 CMS console, restart the C1 CMS site (Tools | Restart Server) and then examine “/bin/Composite.Generated.dll” using a program like .NET Reflector you would see that your data definition is actually a CLR type now, with properties and attributes like, the one shown above.

So – in short – all data schemas are defined as CLR types (interfaces) whether they are defined by C1 CMS (like pages, users, templates etc.), you as a C# developer or users that use the visual data creation tools. And they are all accessible via LINQ.

When you are working with custom IData you typically only define an interface – concrete classes are generated by C1 CMS automatically.

In this document we will go into the technical detail about the C1 CMS IData concept. The intended audience is C# developers who need to create custom data types for use in C1 CMS. The document will describe how to prepare your custom IData for features like publishing workflow, page meta data, content localization and more.