Extension methods for ObjectContext and DbContent to get the mapped table name from an entity.
Table of contents
The problem
I am working on a set of extension methods to perform a bulk insert using Entity Framework, using internally the SqlBulkCopy object. One of the steps involved is to get the mapped table name from an entity. After some google searching, I found a post on StackOverflow that led me to the solution.
The solution
The trick is to use the method ObjectQuery.ToTraceString to generate a SQL Select statement for an entity, and then extract the table name from that statement.
Let’s assume that you have an entity named Album corresponding to a table named dbo.Albums.
// context is ObjectContext string sql = context.CreateObjectSet<T>().ToTraceString(); ...
The generated SQL for that entity can be something like this:
SELECT [Extent1].[AlbumId] AS [AlbumId], [Extent1].[GenreId] AS [GenreId], [Extent1].[ArtistId] AS [ArtistId], [Extent1].[Title] AS [Title], [Extent1].[Price] AS [Price], [Extent1].[AlbumArtUrl] AS [AlbumArtUrl] FROM [dbo].[Albums] AS [Extent1]
So, all we need to do is to parse the SELECT statement to get the table name. This is the approach used in the post above but it has some limitations – that code will work only for tables that are in the default SQL Server schema (dbo.{tableName}). I made some changes to that code and I’m extracting the full table name using regular expressions.
The extension methods
I have created one extension method for DbContext and other for ObjectContext:
public static class ContextExtensions { public static string GetTableName<T>(this DbContext context) where T : class { ObjectContext objectContext = ((IObjectContextAdapter) context).ObjectContext; return objectContext.GetTableName<T>(); } public static string GetTableName<T>(this ObjectContext context) where T : class { string sql = context.CreateObjectSet<T>().ToTraceString(); Regex regex = new Regex("FROM (?<table>.*) AS"); Match match = regex.Match(sql); string table = match.Groups["table"].Value; return table; } }
Using the code
Getting the mapped table name for an entity named Album, using a ObjectContext object:
ObjectContext context = ....; string table = context.GetTableName<Album>();
Or using a DbContext object:
DbContext context = ....; string table = context.GetTableName<Album>();
References
- [StackOverflow] Get Database Table Name from Entity Framework MetaData
- [MSDN] ObjectQuery.ToTraceString Method
If you’re dealing with Entity Framework proxies, you need to change the assignment for entityType to
metadata
.GetItems(DataSpace.OSpace)
.Single(e => objectItemCollection.GetClrType(e).IsAssignableFrom(type));
because the Proxy type is not in the objectItemCollection (but is assignable to type in that collection).
Hi Rui,
Nice blog post. I have a rather very similar requirement with what necessitated this post and was hoping you could help a little bit. First off, (and this might be a silly oversight on my behalf) the DbContext version of the ContextExtension method says “System.Data.Objects.ObjectContext does not contain a definition for GetTableName()”. What am I missing. Secondly, is it at all possible for you to share the rest of your SQLBulkCopy implementation. Many thanks for this.
Hi Ted,
Don’t forget to include the namespace of the extension method (using statement).
Regards,
Rui
http://weblogs.asp.net/ricardoperes/entity-framework-metadata worked for me. I think ObjectContext.GetTableName doesn’t work for Oracle. I too got the same error as Ted. Commented the return line and returned a dummy string so i could debug. The immediate window too said there was no GetTableName.
Thanks Rui anyways.
PS: You can find the code for the SqlBulkCopy here: