Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the column name (sspace) from an ospace property name

I can see from the following example how to get the table name of an OSpace type:

https://lowrymedia.com/2014/06/10/ef6-1-mapping-between-types-tables-including-derived-types/

But how do I go about getting the SSpace column name from an OSpace property name (i.e. CLR type property)?

By browsing the MetadataProperties from the corresponding CSpace property, I can see there is a "Configuration" entry containing the column name if changed using the Fluid API or ColumnAttribute, but the value of the entry is an internal class on EF's part. Is it at all possible?

I have browsed a few answers regarding this topic, but none of them take into account the Fluid API configuration.

P.S. the specific property I'm looking for is scalar, if that can simplify things...

like image 274
HelloWorld Avatar asked Oct 31 '22 00:10

HelloWorld


1 Answers

Column Name

To get the column name, you have to first get the EdmProperty associated with that column in the “structural space” (SSpace). I provide code to do that below. Once you have the EdmProperty, the name of the column is simply EdmProperty.Name:

string GetColumnName(DbContext context, PropertyInfo property) {
    return GetStructuralSpaceEdmProperty(context, property).Name;
}

Structural Space Property

This is based on an article. That article gives you enough information to map all the way to the structural EntityType. I added a bit at the end to do the actual property mapping to get the EdmProperty representing the column. As the article states, these APIs require ≥EntityFramework-6.1.

EdmProperty GetStructuralSpaceEdmProperty(DbContext context, PropertyInfo property) {
    IObjectContextAdapter adapter = context;
    var metadata = adapter.ObjectContext.MetadataWorkspace;

    // First, you map the Object Space to the Conceptual Space.
    var objectItemCollection = (ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace);
    var objectEntityType = metadata.GetItems<EntityType>(DataSpace.OSpace)
        .Single(oet => objectItemCollection.GetClrType(oet) == property.DeclaringType);
    // Note: we are assuming that CSpace and OSpace name their properties the
    // same instead of trying to use EF’s own OSSpace mappings here.
    var conceptualEntityType = metadata.GetItems<EntityType>(DataSpace.CSpace)
        .Single(cet => objectEntityType.Name == cet.Name);
    var conceptualEdmProperty = conceptualEntityType.Properties
        .Single(ep => ep.Name == property.Name);

    // Then you map the conceptual space onto the structural space.
    var entitySet = metadata.GetItems<EntityContainer>(DataSpace.CSpace)
        .Single().EntitySets
        .Single(es => es.ElementType.Name == conceptualEntityType.Name);
    var entityMapping = metadata.GetItems<EntityContainerMapping>(DataSpace.CSSpace)
        .Single().EntitySetMappings
        .Single(esm => esm.EntitySet == entitySet);
    // The entity may be split to different tables or fragments.
    var fragments = entityMapping.EntityTypeMappings
        .SelectMany(etm => etm.Fragments);
    var propertyMappings = fragments.SelectMany(f => f.PropertyMappings);
    // Normal properties will be “ScalarPropertyMapping”.
    // Depending on what information you are seeking or your
    // model, you may be interested in other PropertyMapping.
    var structuralSpaceProperty = propertyMappings
        .OfType<ScalarPropertyMapping>()
        .Single(pm => pm.Property == conceptualEdmProperty).Column;

    return structuralSpaceProperty;
}

Note that once you have EdmProperty in structural space, there are a bunch of other useful properties you can read from it. For example, for SQL Server, EdmProperty.IsUnicode will be true for NVARCHAR/NCHAR and false for VARCHAR/CHAR types whereas this property is not set to a useful value in the conceptual space.

Random Information

Spaces in EF

Alex D. James’s blog post “Tip 10 — How to understand Entity Framework jargon” explains some of the terms of the API which do not make sense on their own. DataSpace.OSpace stands for “Object Space”, meaning the .net POD classes. DataSpace.SSpace stands for “Structural Space”, probably named after “structured” in the term “SQL” and thus meaning it most directly describes the backend database. DataSpace.CSpace stands for “Conceptual Space” which seems intended to be a neutral space which both the “Object Space” and “Structural Space” can map into. DataSpace.OCSpace stands for the mapping from the object space onto the conceptual space. We bypass this mapping because we assume that property names in the object space are the same as in our .net types. DataSpace.CSSpace stands for the mapping of conceptual space onto structural space. We use this mapping because the model may be configured to use a different column name via the fluent API or ColumnAttribute.

API Confusion

The metadata API of EF seems to assume that the consumer of the API has an understanding of the internals of EF to an extent. It is not made in a very type safe way which helps consumers. For example, the fact that we had to use Enumerable.OfType<TResult> to get to ScalarPropertyMapping means that one has to know to expect the collection to have ScalarPropertyMapping instances in it. Likewise, the MetadataWorkspace.GetItems<T>() method requires us to know that the sorts of items one would find in the metadata include EntityType. Thus, a deep understanding of the internals of EF or complete examples are necessary to write code that consumes the mapping portion of these APIs.

like image 80
binki Avatar answered Jan 04 '23 13:01

binki