Tips and Tricks for Debugging your Entity Framework Provider

Here are some tips that may be helpful when developing and testing a data provider that supports Entity Framework:

Tip #1 Validating SchemaInformation SSDL and MSL using EdmGen.exe

When developing an Entity Framework provider, one of the biggest tasks is preparing a store-specific mapping for SchemaInformation schema. Those mappings are quite complicated so it's easy to make a mistake.

You can validate that mapping with EdmGen utility:

1. Create an empty folder

2. Copy System.Data.Resources.DbProviderServices.ConceptualSchemaDefinition.csdl that ships with Sample Provider to that directory

3. Copy MyProvider.StoreSchemaDefinition.ssdl and MyProvider.StoreSchemaMapping.msl to the same place (adjust names as needed)

4. Open cmd.exe, cd to the folder and run (the following is a single line, no line breaks):

%WINDIR%\Microsoft.NET\Framework\v3.5\EdmGen
/mode:validateartifacts
/incsdl:System.Data.Resources.DbProviderServices.ConceptualSchemaDefinition.csdl
/inmsl:MyProvider.StoreSchemaMapping.msl
/inssdl:MyProvider.StoreSchemaDefinition.ssdl 

This will display a list of errors.

Tip #2 Generating a model from a database without using designer

You can use EdmGen.exe /mode:fullgeneration to generate set of schema files (CSDL,SSDL,MSL) from a database. This can be used instead of the designer, when using designer is nor preferable (for example in automated build environments). Since the the ADO.Net Entity Data Model Wizard will perform filtering based against your SchemaInformation schema, and EdmGen.exe does not perform any filtering, Getting things working with EdmGen.exe is a natural first step when debugging your SchemaInformation schema. See EdmGen.exe documentation for more information.

Because EdmGen.exe is just a thin layer on top of System.Data.Entity.Design.dll APIs it is easy to leverage those to get functionality equivalent to EdmGen in your test suite.

Tip #3 Query SchemaInformation using Entity SQL

There's a little-known API that can be used to create an EntityConnection that's based on SchemaInformation. All you have to do is to call CreateStoreSchemaConnection with provider invariant name and connection string. Once you have the EntityConnection, you can use it to query entity sets using Entity SQL.

For example, to list all tables whose names start with 's%' you can use the following code snippet:

 using (EntityConnection ec = EntityStoreSchemaGenerator.CreateStoreSchemaConnection("System.Data.SqlClient", 
                   @"server=.\sqlexpress;integrated security=true"))
{
    ec.Open();
    using (EntityCommand cmd = ec.CreateCommand())
    {
        cmd.CommandText = "SELECT VALUE t.Name FROM SchemaInformation.Tables AS t WHERE t.Name LIKE 's%'";
        using (DbDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
        {
            while (reader.Read())
            {
                Console.WriteLine(reader.GetValue(0));
            }
        }
    }
}

Tip #4 Query SchemaInformation using LINQ To Entities

The same thing can be achieved using LINQ To Entities. We just need to generate appropriate classes with:

EdmGen.exe
/mode:entityclassgeneration
/incsdl:System.Data.Resources.DbProviderServices.ConceptualSchemaDefinition.csdl
/outobjectlayer:SchemaInformation.cs

And then the same query can be written as:

 using (EntityConnection ec = 
        EntityStoreSchemaGenerator.CreateStoreSchemaConnection("System.Data.SqlClient", 
        @"server=.\sqlexpress;integrated security=true"))
{
    using (SchemaInformation si = new SchemaInformation(ec))
    {       
        foreach (Table t in si.Tables.Where(c=>c.Name.StartsWith("s")))
        {
            Console.WriteLine(t.Name);
        }
    }
}

 

Tip #5 Common Error Messages and how to resolve them

  • error 0005: The 'PreferredMapping' attribute is not declared.

PreferredMapping attribute has been removed in Beta3. Remove it from the provider manifest XML file. Preferred mapping for each type is now resolved with GetEdmType() GetStoreType() functions - see our breaking changes details.

  • error 2041: There is no store type that maps to edm type '*' with the following facet values '*'. Please change the type or facets of property 'Id' in csdl to match with one of the store types.

Make sure that the provider manifest declares a type whose facets are compatible with your CSDL property. Using beta3, you may be able to work around the problem by adding an artificial type to the provider manifest just to satisfy mapping requirements. Post-beta3 we have changed mapping validation rules and we now ignore facet information in CSDL when validating mapping.

  • You get a store error that refers to EDM types (Int32, Int16, String) instead of store types (varchar, number, etc.)

In EF Beta3 the query tree that is sent to the provider has nodes annotated with conceptual types (not store types like in previous releases). You need to convert from C to S types. If your provider is based on Sample Provider you need to modify GetSqlPrimitiveType method in SqlGenerator.cs.

  • The given key was not present in the dictionary."; code 6003.

You may see this exception when the provider returns column Ordinal values which are zero-based instead of one-based. System.Data.Entity.Design APIs expect column ordinals to be one-based.