Writing an EF-enabled ADO.NET Provider - Part 2

 


The information in this post is out of date.

Visit msdn.com/data/ef for the latest information on current and past releases of EF.


Part 2: Provider Manifest

This article outlines how to write the provider manifest for our Entity Framework Provider. We will walk through the different components needed, and look at some important parts of the code. Please make sure to read the intro article before you continue. When you are finished reading, I encourage you to download and play with the code samples included in this post.

What is a Provider Manifest

The provider manifest is an essential component of our provider. It creates the mapping between database types and EDM types. Additionally, the manifest may also contain mappings for built-in SQL functions. For more details on the manifest, be sure to check its specification on MSDN.

Who Calls the ProviderManifest?

ProviderServices, which sits above the manifest, invokes the ProviderManifest during the command creation. We will look at command creation in more detail in our Query Pipeline post.

ADO.NET Provider uses the function overrides described within the class. These functions are originally defined in System.Data.Common as MustOverride.

Manifest Components

The manifest consists of four pieces:

· ProviderManifest.xml – this file is the provider manifest. It declares the mappings between SQL and EDM Types.

· ProviderManifest.cs– handles the loading of the mapping schema.

· Database Mapping Files

· ProviderManifest Schema Mapping.msl – contains a set of EntitySetMappings for everything from a Table to Functions, Procedures, etc.

· ProviderManifest Schema Description.ssdl – This file defines for the underlying store.

In this post, we will only look at ProviderManifest.xml and ProviderManifest.cs in depth. The database mapping files included here are identical to those in the Sample EF Provider, and are designed to work with a SQL Server 2008 database.

The Code

ProviderManifest.cs

This file is in charge of loading the database mapping files as well as the provider manifest document. Here is the constructor for the ProviderManifest class:

1.

2.

3.

4.

5.

6.

7.

8.

public ProviderManifest(string manifestToken)

    : base(CustomProviderManifest.GetProviderManifest())

{

    // GetStoreVersion will throw ArgumentException if manifestToken is null, empty, or not recognized.

    _version = StoreVersionUtils.GetStoreVersion(manifestToken);

    _token = manifestToken;

}

In the constructor, we load the manifest via GetProviderManifest() and set up basic properties of the provider such as version and token.

A section of the ProviderManifest class is dedicated to override functions described above. An example of these is GetStoreTypes(), which returns the list primitive types as described in our manifest.

ProviderManifest.xml

ProviderManifest.cs loads the provider manifest, making it available to the ADO.NET provider. For our project, this file will be very short as we are only supporting three basic types. Here is what the entire file will look like:

1.

2.

3.

4.

5.

6.

7.

8.

9.

10.

11.

12.

13.

14.

15.

16.

17.

<?xml version="1.0" encoding="utf-8"?>

<ProviderManifest Namespace="SqlServer" xmlns="https://schemas.microsoft.com/ado/2006/04/edm/providermanifest">

  <Types>

    <Type Name="int" PrimitiveTypeKind="Int32">

    </Type>

    <Type Name="nvarchar" PrimitiveTypeKind="String">

      <FacetDescriptions>

        <MaxLength Minimum="1" Maximum="4000" DefaultValue="4000" Constant="false" />

        <Unicode DefaultValue="true" Constant="true" />

        <FixedLength DefaultValue="false" Constant="true" />

      </FacetDescriptions>

    </Type>

    <Type Name="bit" PrimitiveTypeKind="Boolean">

    </Type>

  </Types>

</ProviderManifest>

The Types node describes the mapping between the store types and the EDM primitive types. In our case, the Int and Boolean type mappings are straightforward.

The String mapping is a bit more complex, as it contains a series of facet descriptions. You can think of these as constraints on the type.

Note that we have the freedom to choose the store types to which we map our EDM Types. For instance, we could have chosen to map our strings to varchar. Every time we pick a store type to map to, we must be mindful of how this will affect the applications built on top of our provider.

Mapping to Built-in SQL Functions

We can use the Function tag to map to a built-in SQL Function. Below is a function to compute averages for Int32’s.

1.

2.

3.

4.

5.

6.

  <Functions>

    <Function Name="AVG" Aggregate="true" BuiltIn="true">

      <ReturnType Type="Int32" />

      <Parameter Name="arg" Type="Collection(Int32)" Mode="In" />

    </Function>

  <Functions>

Functions are declared after types, and before the closing </ProviderManifest> tag. The function above would compute the average for a collection of Ints.

Conclusion

The provider manifest is a simple but essential part of our EF data provider. The manifest is the place where we establish the mappings between EDM and store types. After creating the mappings above, our provider will be able to use ints, strings, and Booleans, which are the minimum types required to get the provider up and running. Once created, they allow the developer to code using the EDM types without having to worry about type conversions.

· Part 1: Provider Overview

· Part 3: Query Pipeline, ProviderServices, ProviderFactory (Coming soon)

· Part 4: Writing the Update Pipeline, and Sample Code (Coming soon)

Thank you
Pedro Ardila
Entity Framework PM