Public Mapping API

An Entity Framework model is composed of a conceptual model, a store model and a mapping between them. Within an .edmx file (XML-based), the three components are described using CSDL (Conceptual Schema Definition Language), SSDL (Store Schema Definition Language) and respectively MSL (Mapping Specification Language). Entity Framework stores and handles this metadata in-memory using a custom object model. It includes classes that define concepts equivalent to their XML counterparts, but tailored for in-memory manipulation. These classes provide APIs that can be used to retrieve information or update the metadata as needed.

The Mapping APIs consist of classes from the object model that specify and handle the mapping metadata. Entity Framework uses the mapping metadata at runtime to translate queries against the conceptual model to store-specific commands. In previous releases the Mapping APIs were not public. By exposing these low-level APIs Entity Framework provides access to mapping information at runtime and enables programability of the mapping space. However the full spectrum of scenarios where they could prove useful has not been explored yet.

The classes that are part of the Mapping APIs are found under the System.Data.Entity.Core.Mapping namespace. The mapping metadata is basically represented by a tree of mapping items (deriving from the MappingItem base class). On each level a mapping-item defines the mapping between a conceptual and a store item from a corresponding level in the trees of conceptual, respectively store items. In general the tree structure is similar to what the MSL defines, except a few cases where MSL is more compact. The root of the mapping-item tree is the EntityContainerMapping class.

The mapping-item tree is exposed through the DbModel.ConceptualToStoreMapping property. An instance of the DbModel class is available as parameter of the Apply method in code-first conventions (classes that implement IConceptualModelConvention<T>, respectively IStoreModelConvention<T>). However, the mapping-item tree is constructed only after the conceptual model conventions are applied and thus is fully available only in the store model conventions. In this case the metadata model is mutable, so the Mapping APIs can be used to both retrieve and update mapping information.

After being built or loaded from XML the metadata is stored within the MetadataWorkspace associated with an ObjectContext. In case of DbContext the metadata workspace can be retrieved using ((IObjectContextAdapter)dbContext).ObjectContext.MetadataWorkspace. At this stage the metadata model is immutable. Attempts to modify it result in InvalidOperationException being thrown, with an error message indicating the read-only state. The Mapping APIs that query information from the metadata model will continue working. The access point for the mapping metadata is the StorageMappingItemCollection class. An instance of this class can be retrieved by calling (StorageMappingItemCollection)MappingWorkspace.GetItemCollection(DataSpace.CSSpace). Further, the entity container mappings can be obtained using the StorageMappingItemCollection.GetItems<EntityContainerMapping>() method.

Example

The code below is an example of how to change the name of a column associated with a property, using a store model convention and the mapping API. By default EF creates a column named “Description” in the table “MyTable” to store values for the Description property of Entity. The example changes the name of that column to “MyColumn”.

[Table("MyTable")]
public class Entity
{
    public int Id { get; set; }
    public string Description { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<entity> Entities { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Add(new MyConvention());
    }
}

public class MyConvention : IStoreModelConvention<EdmModel>
{
    public void Apply(EdmModel item, DbModel model)
    {
        // Find the property mapping that maps the Description property
        // from the conceptual model to the corresponding property from 
        // the store model.
        var propertyMapping
            = model.ConceptualToStoreMapping
                .EntitySetMappings.Single()
                .EntityTypeMappings.Single(etm => etm.EntityType.Name == "Entity")
                .Fragments.Single()
                .PropertyMappings.Single(pm => pm.Property.Name == "Description");

        // The mapping involves scalar properties.
        var scalarPropertyMapping = (ScalarPropertyMapping)propertyMapping;

        // ScalarPropertyMapping.Column provides the corresponding EdmProperty
        // from the store model, which represents the table column.
        scalarPropertyMapping.Column.Name = "MyColumn";
    }
}

Last edited Mar 25, 2014 at 9:16 PM by RoMiller, version 5

Comments

moozzyk Mar 25, 2014 at 5:02 PM 
@bpchrist13 - here is a project I created that allows for using store functions in Code First - https://codefirstfunctions.codeplex.com/

bpchrist13 Mar 25, 2014 at 4:46 PM 
Can someone at Microsoft please post an example to wire up a custom scalar function starting form OnModelCreating withing the DbContext.

My example is that I want to use linq to entities to cast a string to a type (decimal or datetime) do a comparison. I'm using code-first and do not want to include an edmx file.

soadyp Mar 23, 2014 at 12:54 PM 
Hi Rowan, does this mean we can dynamically declare a datamodel now.?
Now that would be nice