There are a few limitations of Entity Framework 6.x that require various work-arounds. One of those limitations is not being able to take direct advantage of entity mappings that are defined. However, it is possible to utilize Entity Framework’s API’s to retrieve and consume this information.
Entity Framework provides a “MetadataWorkspace” API that allows retrieve all information about an entity. The code below shows how to retrieve the “EntitySetMapping,” which contains all information about an Entity.
public EntitySetMapping GetMapping(Type type) { var metadata = ((IObjectContextAdapter)this.DbContext).ObjectContext.MetadataWorkspace; var objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace)); var entityType = metadata.GetItems<EntityType>(DataSpace.OSpace).Single(t => objectItemCollection.GetClrType(t) == type); var entitySet = metadata.GetItems<EntityContainer>(DataSpace.CSpace).Single().EntitySets.Single(s => s.ElementType.Name == entityType.Name); var mapping = metadata.GetItems<EntityContainerMapping>(DataSpace.CSSpace).Single().EntitySetMappings.Single(s => s.EntitySet == entitySet); return mapping; }
The code below shows how to use the EntitySetMapping to retrieve the name of the table to which an entity is mapped.
public string GetTableName(Type type) { var mapping = GetMapping(type); var tableEntitySet = mapping.EntityTypeMappings.Single().Fragments.Single().StoreEntitySet; var tableName = tableEntitySet.MetadataProperties["Table"].Value ?? tableEntitySet.Name; return tableName.ToString(); }
This can be taken a step further to get a specific column name to which a property is mapped via a LINQ expression.
private string GetColumnName(string propertyName, EntitySetMapping mapping) { var columnName = mapping.EntityTypeMappings.Single().Fragments.Single().PropertyMappings.OfType<ScalarPropertyMapping>().Single(m => m.Property.Name == propertyName).Column.Name; return columnName; } public string GetColumnName(Expression<Func<TEntity, object>> expression) { var propertyName = StaticHelpers.GetPropertyName(expression); var mapping = GetMapping(typeof(TEntity)); return GetColumnName(propertyName, mapping); }
The exposed public method “GetColumnName” can then be called like this for any arbitrary Entity and a property expression:
var columnName = GetColumnName<MyClass>(x => x.MyProperty);
Finally, here’s another helper that would return a Dictionaty<string, string> that shows the mappings between all properties and database columns.
public Dictionary<string, string> GetColumnNames(Type type) { var dict = new Dictionary<string, string>(); var mapping = GetMapping(type); var propertyMappings = mapping.EntityTypeMappings.Single().Fragments.Single().PropertyMappings.OfType<ScalarPropertyMapping>().ToList(); foreach (var propertyMapping in propertyMappings) { var propertyName = propertyMapping.Property.Name; var columnName = propertyMapping.Column.Name; if (!string.IsNullOrEmpty(propertyName) && !string.IsNullOrWhiteSpace(columnName) && !dict.ContainsKey(propertyName)) { dict.Add(propertyName, columnName); } } return dict; }
Now, you may ask “why would I want to do this?” Well, the primary use case is building queries, manually, yet keeping them type-safe. Another use case is utilizing the mappings to map a return set of data to specific class/object types. I have another post that illustrates the latter coming soon.