Click here to Skip to main content
15,888,527 members
Articles / Programming Languages / C#

Entity Framework: Get Mapped Table Name from an Entity

Rate me:
Please Sign up or sign in to vote.
4.91/5 (8 votes)
19 Mar 2012CPOL1 min read 83.3K   6   8
Extension methods for ObjectContext and DbContent to get the mapped table name from an entity

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 searching on Google, 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.

C#
// context is ObjectContext
string sql = context.CreateObjectSet<T>().ToTraceString();

...

The generated SQL for that entity can be something like this:

SQL
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 another for ObjectContext:

C#
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:

C#
ObjectContext context = ....;
string table = context.GetTableName<Album>();

Or using a DbContext object:

C#
DbContext context = ....;
string table = context.GetTableName<Album>();

References

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Italy Italy
My name is Rui Jarimba and I was born in Madeira island, Portugal and I currently live in Rome, Italy.

I have more than 10 years of experience developing software using the .NET Framework and other technologies (Web development, Databases, ...).

Some of my professional interests are: software development best practices, software architecture, cloud computing, Continuous Integration (CI), Continuous Delivery (CD) and agile methodologies such as Scrum, Kanban, Lean and any other methodology that can help me to become a better and more productive software engineer.

I believe in good code - code that is readable, maintainable, reusable, testable and deployable. This means that I'm not the "quick and dirty" type, I write code for the medium/long term whenever possible.

Something else about me - I love music, I am an amateur photographer, not a big fan of gyms (I prefer to do some outdoor activity such as walking/hiking), big foodie (I love Mediterranean cuisine and my glass of wine!).

Comments and Discussions

 
QuestionExplanation of the Regex Pin
reggaeguitar5-Nov-14 11:29
reggaeguitar5-Nov-14 11:29 
QuestionHow do I convert entity and property names (conceptual model) to table and column names (database store)? (Uses reflection.) Pin
Robert Gustafson23-Jun-14 11:14
Robert Gustafson23-Jun-14 11:14 
I plan to add supplementary (unique) indexes to my entities' tables. Since I can't have more than one EF key for an entity, the other indexes need to be created using CONSTRAINT SQL, which in turns means converting between entity and property names (conceptual model) and table and column names (database store). I've taken the following code from another person (and converted it to VB):

Imports System.Data.Objects
Imports System.Data.Entity
Imports System.Data.SqlClient
Imports System.Data.EntityClient
Imports System.Data.Metadata.Edm
Imports System.Data.Objects.DataClasses
Imports System.Linq.Expressions
Imports System.Runtime.Serialization
Imports System.Reflection

Public Class ConvertConceptualToStore
    Private Shared Function GetTableName(Of T As EntityObject)() As String
    Dim type As Type = GetType(T)
    Dim at As EdmEntityTypeAttribute = GetAttribute(Of EdmEntityTypeAttribute)(type)
    Return at.Name
    End Function

    Private Shared Function GetColumnName(Of T As EntityObject) _
        (ByVal propertySelector As Expression(Of Func(Of T, Object))) As String

    If propertySelector Is Nothing Then
        Throw New Exception("""" &amp; propertySelector.ToString &amp; """ is null.")
    End If

    Dim propertyInfo As PropertyInfo = GetPropertyInfo(propertySelector.Body)
    Dim attribute As DataMemberAttribute = _
        GetAttribute(Of DataMemberAttribute)(propertyInfo)
    If String.IsNullOrEmpty(attribute.Name) Then
        Return propertyInfo.Name
    Else
        Return attribute.Name
    End If
    End Function

    Private Shared Function GetAttribute(Of T As Class)(ByVal memberInfo As MemberInfo) As T
    If memberInfo Is Nothing Then
        Throw New Exception("""" &amp; memberInfo.ToString &amp; """ is null.")
    End If

    Dim customAttributes() As Object = _
        memberInfo.GetCustomAttributes(GetType(T), False)
    Dim attribute As T = _
        DirectCast(customAttributes.Where(Function(a) TypeOf a Is T).First(), T)
    Return attribute
    End Function

    Private Shared Function GetPropertyInfo(ByVal propertySelector As Expression) As PropertyInfo
    If propertySelector Is Nothing Then
        Throw New Exception("""" &amp; propertySelector.ToString &amp; """ is null.")
    End If

    Dim memberExpression As MemberExpression = _
        TryCast(propertySelector, MemberExpression)
    If memberExpression Is Nothing Then
        Dim unaryExpression As UnaryExpression = _
            TryCast(propertySelector, UnaryExpression)
        If unaryExpression IsNot Nothing _
                AndAlso unaryExpression.NodeType = ExpressionType.Convert Then
            memberExpression = TryCast(unaryExpression.Operand, MemberExpression)
        End If
    End If
    If memberExpression IsNot Nothing _
            AndAlso memberExpression.Member.MemberType = MemberTypes.Property Then
        Return DirectCast(memberExpression.Member, PropertyInfo)
    Else
        Throw New ArgumentException("No property reference was found.", "propertySelector")
    End If
    End Function

    ' Invocation example
    Public Shared Sub Test()
    Dim table As String = GetTableName(Of Entity)()
    Dim column As String = GetColumnName(Of Entity)(Function(Location) Entity.Property)
    End Sub
End Class


I need to know some things:

1. I don't need an ObjectContext for this code, do I?
2. What if the property I need to convert to a field is part of a
complex property? Do I need to augment or modify the code for such a
situation? (i.e., Suppose I have an entity called Location, with a
complex property of Address, and I need to get the field for
Address.Street. Do I just use,
columnName = GetColumnName(Of Location)(Function(Location) Location.Address.Street),
or do I have to do something more?)
3. Suppose my code doesn't know beforehand the names of my entity and
property. Is there a way to adapt this code to take a _String value_
for each (at least for the property name; i.e., "Entity.Property"), then find the
appropriate class/property reference therefrom?

Please answer these questions ASAP!

QuestionThe same "alternative approach" in VB 2010 Pin
Robert Gustafson29-May-14 6:30
Robert Gustafson29-May-14 6:30 
QuestionAn alternative approach Pin
Ackroyddd11-Dec-12 1:35
Ackroyddd11-Dec-12 1:35 
AnswerRe: An alternative approach Pin
Robert Gustafson29-May-14 6:40
Robert Gustafson29-May-14 6:40 
SuggestionMake Oracle friendly Pin
Mark Johnston (SSCGP)26-Mar-12 9:46
Mark Johnston (SSCGP)26-Mar-12 9:46 
GeneralRe: Make Oracle friendly Pin
Rui Jarimba26-Mar-12 9:56
professionalRui Jarimba26-Mar-12 9:56 
SuggestionUpdate to include option for Schema in SQL Server Pin
Mark Johnston (SSCGP)26-Mar-12 9:42
Mark Johnston (SSCGP)26-Mar-12 9:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.