The CSDL schema supports (what we internally call) annotations. Basically, annotations are XML attributes from a custom XML namespace that are part of your EntityType’s definition.

Here’s an example of an EntityType in CSDL with annotations. Notice that entity properties can have annotations too:

<EntityType

  Name="Customers"

  xmlns:attr="http://tempuri.org/MyCustomNamespace"

  attr:MyCustomAnnotation="ExampleAnnotation">

 

  <Key>

   <PropertyRef Name="CustomerID" />

  </Key>

 

  <Property Name="CustomerID" Type="String" Nullable="false"

   MaxLength="5" FixedLength="true"

   xmlns:attr="http://tempuri.org/MyCustomNamespace"

    attr:MyCustomAnnotation="ExampleAnnotation" />

 

  <!-- other properties -->

</EntityType>

 

A cursory glance at System.Data.Resources.CSDLSchema.xsd sitting in %vsinstalldir%\Xml\Schemas will tell you that pretty much all elements in CSDL allow attributes from a custom namespace. In fact, the <Schema /> element even allows elements from a custom XML namespace.

The real beauty of CSDL annotations is that the Entity Framework loads them into the metadata system when it loads the CSDL and you can access them as metadata properties via the public metadata APIs.

The following code snippet uses the metadata APIs to extract and dump CSDL annotations for the EntityType declared above:

using System;

using System.IO;

using System.Xml;

using System.Linq;

using System.Collections.Generic;

using System.Data.Metadata.Edm;

 

namespace ConsoleApplication1

{

  class Program

  {

    static void Main(string[] args)

    {

      string schema = @"

        <Schema Namespace='CNorthwind' Alias='Self'

          xmlns:cg='http://schemas.microsoft.com/ado/2006/04/codegeneration'

          xmlns:edm='http://schemas.microsoft.com/ado/2006/04/edm'

          xmlns='http://schemas.microsoft.com/ado/2006/04/edm'>

 

          <EntityType Name='Customer'

            xmlns:attr='http://tempuri.org/MyCustomNamespace'

            attr:MyCustomAnnotation='EntityAnnotation'>

 

            <Key>

              <PropertyRef Name='CustomerID' />

            </Key>

 

            <Property Name='CustomerID' Type='String' MaxLength='1024'

              Nullable='false'

              xmlns:attr='http://tempuri.org/MyCustomNamespace'

              attr:MyCustomAnnotation='PropertyAnnotation' />

 

            <Property Name='Address' Type='String' MaxLength='1024'

              Nullable='false' />

            <Property Name='City' Type='String' MaxLength='1024'

              Nullable='false' />

            <Property Name='CompanyName' Type='String' MaxLength='1024'

              Nullable='false' />

            <Property Name='ContactName' Type='String' MaxLength='1024'

              Nullable='false' />

            <Property Name='ContactTitle' Type='String' MaxLength='1024'

              Nullable='false' />

            <Property Name='Country' Type='String' MaxLength='1024'

              Nullable='false' />

            <Property Name='Fax' Type='String' MaxLength='1024'

              Nullable='false' />

            <Property Name='Phone' Type='String' MaxLength='1024'

              Nullable='false' />

            <Property Name='PostalCode' Type='String' MaxLength='1024'

              Nullable='false' />

            <Property Name='Region' Type='String' MaxLength='1024'

              Nullable='false' />

          </EntityType>

 

          <EntityContainer Name='NorthwindContext'>

            <EntitySet Name='Customers' EntityType='Self.Customer' />

          </EntityContainer>

        </Schema>";

 

      string myXmlns = "http://tempuri.org/MyCustomNamespace";

      EdmItemCollection collection = new EdmItemCollection(

        new XmlReader[]

        {

          XmlReader.Create(new StringReader(schema))

        }

      );

 

      foreach (EntityType entityType in collection.GetItems<EntityType>())

      {

        // Dump annotations on EntityType

        IEnumerable<MetadataProperty> entityAnnotations =

          entityType.MetadataProperties.Where(prop => prop.Name.StartsWith(myXmlns));

        foreach (MetadataProperty entityAnnotation in entityAnnotations)

        {

          Console.WriteLine("Entity: {0},\n\tAttribute: {1}\n\tValue: {2}",

            entityType.Name, entityAnnotation.Name, entityAnnotation.Value);

        }

 

        // Dump annotations on properties of EntityType

        foreach (EdmProperty entityProperty in entityType.Properties)

        {

          IEnumerable<MetadataProperty> propertyAnnotations =

            entityProperty.MetadataProperties.Where(prop => prop.Name.StartsWith(myXmlns));

          foreach (MetadataProperty propertyAnnotation in propertyAnnotations)

          {

            Console.WriteLine("Property {0},\n\tAttribute: {1}\n\tValue: {2}", entityProperty.Name, propertyAnnotation.Name, propertyAnnotation.Value);

          }

      }

 

      Console.ReadKey();

    }

  }

}

 

Btw, ADO.NET Data Services (code name Astoria) makes heavy use of CSDL annotations as described in their design notes.

 

Sanjay Nagamangalam
Program Manager, ADO.NET