The first feature of ADO.NET Orcas that we will examine is the capability to model entities from a conceptual level of abstraction. This approach leverages a set of XML schemas (which are useful for defining entities) and maps them to the physical persistence layer. These XML files will be parsed by a tool to generate the corresponding .NET implementation code. Whenever we do that, we speak about Entity Data Modeling (EDM).
The first XML metadata file we will examine is the Conceptual Schema Definition Language (CSDL) file, which defines the entity side of our application framework. A file of this type describes each EntityType (a specific entity), EntitySet (group of entities), and Association (relationship between entities).
In Listing A-4, you can see an excerpt of our Northwind CSDL metadata file, describing the Customer and Order entities.
Listing A-4: The Customer and Order EntityType definition within Northwind.CSDL
![]() |
<?xml version="1.0" encoding="utf-8"?> <Schema Namespace="NorthwindModel" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2006/04/edm"> <EntityContainer Name="NorthwindEntities"> <EntitySet Name="Customers" EntityType="NorthwindModel.Customer" /> <EntitySet Name="Orders" EntityType="NorthwindModel.Order" /> <AssociationSet Name="Relationship_Orders_Customers" Association="NorthwindModel.Relationship_Orders_Customers"> <End Role="Customer" EntitySet="Customers" /> <End Role="Order" EntitySet="Orders" /> </AssociationSet> </EntityContainer> <EntityType Name="Customer" Key="CustomerID"> <Property Name="CustomerID" Type="String" Nullable="false" MaxLength="4000" FixedLength="true" /> <Property Name="CompanyName" Type="String" Nullable="false" MaxLength="4000" /> <Property Name="ContactName" Type="String" MaxLength="4000" /> <Property Name="Country" Type="String" /> <NavigationProperty Name="Orders" Relationship="NorthwindModel.Relationship_Orders_Customers" FromRole="Customer" ToRole="Order" /> </EntityType> <EntityType Name="Order" Key="OrderID"> <Property Name="OrderID" Type="Int32" Nullable="false" /> <Property Name="OrderDate" Type="DateTime" /> <Property Name="RequiredDate" Type="DateTime" /> <Property Name="ShippedDate" Type="DateTime" /> <NavigationProperty Name="Customer" Relationship="NorthwindModel.Relationship_Orders_Customers" FromRole="Order" ToRole="Customer" /> </EntityType> <Association Name="Relationship_Orders_Customers"> <End Role="Customer" Type="NorthwindModel.Customer" Multiplicity="0..1" /> <End Role="Order" Type="NorthwindModel.Order" Multiplicity="*" /> </Association> </Schema>
![]() |
This file defines an EntityContainer, named NorthwindEntities, which contains a couple of EntitySets, called Customers and Orders. Customers is a list of entities of type Customer, and Orders is a set of Order instances. There is also a relationship, called Relationship_Orders_Customers, that describes how to traverse the object graph of Customer and Order instances, using the definition of an Association between them.
As you can see, this code fragment describes only entities, without any kind of reference to the database, and all the Customer and Order properties are defined using only .NET types. The schema also describes validation rules and constraints that will also be made available in our code, as specific validation code.
A second XML metadata file to consider is the Storage Schema Definition Language (SSDL) file, which describes the physical data layer. Listing A-5 provides an example.
Listing A-5: The physical data layer Customer and Order definition within Northwind.SSDL
![]() |
<?xml version="1.0" encoding="utf-8"?> <Schema Namespace="Northwind" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2006/04/edm/ssdl"> <EntityContainer Name="dbo"> <EntitySet Name="Customers" EntityType="Northwind.Customer" Schema="dbo" Table="Customers" /> <EntitySet Name="Orders" EntityType="Northwind.Order" Schema="dbo" Table="Orders" /> <AssociationSet Name="FK_Orders_Customers" Association="Northwind.FK_Orders_Customers"> <End Role="Customer" EntitySet="Customers" /> <End Role="Order" EntitySet="Orders" /> </AssociationSet> </EntityContainer> <EntityType Name="Customer" Key="CustomerID"> <Property Name="CustomerID" Type="nchar" Nullable="false" /> <Property Name="CompanyName" Type="nvarchar" Nullable="false" /> <Property Name="ContactName" Type="nvarchar" /> <Property Name="Country" Type="nvarchar" /> </EntityType> <EntityType Name="Order" Key="OrderID"> <Property Name="OrderID" Type="int" Nullable="false" StoreGeneratedPattern="identity" /> <Property Name="CustomerID" Type="nchar" /> <Property Name="OrderDate" Type="datetime" /> <Property Name="RequiredDate" Type="datetime" /> <Property Name="ShippedDate" Type="datetime" /> </EntityType> <Association Name="FK_Orders_Customers"> <End Role="Customer" Type="Northwind.Customer" Multiplicity="0..1" /> <End Role="Order" Type="Northwind.Order" Multiplicity="*" /> <ReferentialConstraint FromRole="Customer" ToRole="Order" FromProperty="CustomerID" ToProperty="CustomerID" /> </Association> </Schema>
![]() |
Unlike the CSDL file, this XML document has explicit references to the physical data structure- such as primary keys, nullability rules, identities, foreign key constraints, and data types related to the SQL Server side. In this example, the two CSDL and SSDL files are quite similar, because we are defining a very simple situation. In real-world applications, these files will probably hold more complex and less symmetric code.
The last metadata file to consider is the Mapping Schema Language (MSL) file, which simply maps the two previous metadata definition files. In Listing A-6, you can see a sample mapping file.
Listing A-6: CSDL and SSDL mapping described by Northwind.MSL
![]() |
<?xml version="1.0" encoding="utf-8"?> <Mapping cs:Space="C-S" xmlns:cs="urn:schemas-microsoft-com:windows:storage:mapping:CS" xmlns="urn:schemas-microsoft-com:windows:storage:mapping:CS"> <cs:EntityContainerMapping cs:StorageEntityContainer="dbo" cs:CdmEntityContainer="NorthwindEntities"> <cs:EntitySetMapping cs:Name="Customers" cs:TableName="Customers" cs:TypeName="NorthwindModel.Customer"> <cs:ScalarProperty cs:Name="CustomerID" cs:ColumnName="CustomerID" /> <cs:ScalarProperty cs:Name="CompanyName" cs:ColumnName="CompanyName" /> <cs:ScalarProperty cs:Name="ContactName" cs:ColumnName="ContactName" /> <cs:ScalarProperty cs:Name="Country" cs:ColumnName="Country" /> </cs:EntitySetMapping> <cs:EntitySetMapping cs:Name="Orders" cs:TableName="Orders" cs:TypeName="NorthwindModel.Order"> <cs:ScalarProperty cs:Name="OrderID" cs:ColumnName="OrderID" /> <cs:ScalarProperty cs:Name="OrderDate" cs:ColumnName="OrderDate" /> <cs:ScalarProperty cs:Name="RequiredDate" cs:ColumnName="RequiredDate" /> <cs:ScalarProperty cs:Name="ShippedDate" cs:ColumnName="ShippedDate" /> </cs:EntitySetMapping> <cs:AssociationSetMapping cs:Name="Relationship_Orders_Customers" cs:TypeName="NorthwindModel.Relationship_Orders_Customers" cs:TableName="Orders"> <cs:EndProperty cs:Name="Customer"> <cs:ScalarProperty cs:Name="CustomerID" cs:ColumnName="CustomerID" /> </cs:EndProperty> <cs:EndProperty cs:Name="Order"> <cs:ScalarProperty cs:Name="OrderID" cs:ColumnName="OrderID" /> </cs:EndProperty> <cs:Condition cs:ColumnName="CustomerID" cs:IsNull="false" /> </cs:AssociationSetMapping> </cs:EntityContainerMapping> </Mapping>
![]() |
You can see that this last file explicitly maps metadata between the conceptual model (CdmEntityContainer) and the physical storage (StorageEntityContainer), defining the containing table (TableName) and column (ColumnName) for each scalar property (Name) of each entity (TypeName).
These files can be defined by hand, as we did in our examples, just by using XML Schema IntelliSense. Or they can be generated by using the Visual Studio Orcas file template named “ADO.NET Entity Data Model,” which starts a simple wizard that produces the files based on user input. Regardless of how the metadata files are produced, after they are defined within a Visual Studio Orcas project they are automatically parsed to dynamically create their corresponding .NET code. The result is a code file that contains definitions of all the EntityType, EntitySet, and Association types defined within the CSDL file. While CSDL is converted in code, SSDL and MSL remain in XML so that they can change the physical layer without changing the conceptual model.