One of the most popular posts on my blog has been EF6.1 Mapping Between Types & Tables. Someone asked me this week about getting the property/column mapping in addition to the type/table mapping. There isn’t a whole lot to say (other than the code is horrible and this will look a whole lot better in EF7), so here is the code.
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Mapping;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Linq;
namespace MappingDemo
{
class Program
{
static void Main(string[] args)
{
using (var db = new BlogContext())
{
Console.WriteLine("Blog.BlogId maps to: {0}", GetColumnName(typeof(Blog), nameof(Blog.BlogId), db));
Console.WriteLine("Post.Body maps to: {0}", GetColumnName(typeof(Post), nameof(Post.Body), db));
}
}
public static string GetColumnName(Type type, string propertyName, DbContext context)
{
var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;
// Get the part of the model that contains info about the actual CLR types
var objectItemCollection = ((ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace));
// Get the entity type from the model that maps to the CLR type
var entityType = metadata
.GetItems<EntityType>(DataSpace.OSpace)
.Single(e => objectItemCollection.GetClrType(e) == type);
// Get the entity set that uses this entity type
var entitySet = metadata
.GetItems<EntityContainer>(DataSpace.CSpace)
.Single()
.EntitySets
.Single(s => s.ElementType.Name == entityType.Name);
// Find the mapping between conceptual and storage model for this entity set
var mapping = metadata.GetItems<EntityContainerMapping>(DataSpace.CSSpace)
.Single()
.EntitySetMappings
.Single(s => s.EntitySet == entitySet);
// Find the storage entity set (table) that the entity is mapped
var tableEntitySet = mapping
.EntityTypeMappings.Single()
.Fragments.Single()
.StoreEntitySet;
// Return the table name from the storage entity set
var tableName = tableEntitySet.MetadataProperties["Table"].Value ?? tableEntitySet.Name;
// Find the storage property (column) that the property is mapped
var columnName = mapping
.EntityTypeMappings.Single()
.Fragments.Single()
.PropertyMappings
.OfType<ScalarPropertyMapping>()
.Single(m => m.Property.Name == propertyName)
.Column
.Name;
return tableName + "." + columnName;
}
}
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>()
.ToTable("t_blog");
modelBuilder.Entity<Blog>()
.Property(b => b.BlogId)
.HasColumnName("blog_id");
modelBuilder.Entity<Post>()
.ToTable("t_post");
modelBuilder.Entity<Post>()
.Property(b => b.Body)
.HasColumnName("post_body");
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
}