15

To get database table name on Entity framework 4.0 I do:

ObjectSetInstance.EntitySet.ToString()

Is there a way to do this on Entity Framework 4.1?

Alexandre
  • 7,004
  • 5
  • 54
  • 72

7 Answers7

25

Extension methods for DbContext and 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 a ObjectContext object:

ObjectContext context = ....;
string table = context.GetTableName<Foo>();

Using a DbContext object:

DbContext context = ....;
string table = context.GetTableName<Foo>();

More info here:

Entity Framework: Get mapped table name from an entity

Rui Jarimba
  • 11,166
  • 11
  • 56
  • 86
  • 1
    I get "Cannot resolve symbol 'GetTableName'" on the line `return objectContext.GetTableName();` in the `DbContext` version. – ProfK Jun 08 '13 at 06:50
  • @ProfK: do you have the extension methods in the same class? – Rui Jarimba Jun 08 '13 at 10:58
  • No, they're in an extensions class like all my extensions. I can't make my DbContext class static. – ProfK Jun 08 '13 at 13:04
  • @ProfK: sorry but I don't understand what you're trying to say.... Why would you make your DbContext class static? – Rui Jarimba Jun 09 '13 at 10:46
  • I don't. I thought you meant did I have extension methods in the same class as my DbSet. My bad. – ProfK Jun 09 '13 at 15:16
8

As of EF6.1, the solution explored in this article shows how to use the newly exposed metadata to accomplish this, should not require the database to be initialized or depend on what method was used to set the table name.

public static string GetTableName<T>(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) == typeof(T));

    // 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 table = mapping
        .EntityTypeMappings.Single()
        .Fragments.Single()
        .StoreEntitySet;

    // Return the table name from the storage entity set
    return (string)table.MetadataProperties["Table"].Value ?? table.Name;
}
Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Avi Cherry
  • 3,996
  • 1
  • 26
  • 31
6

Try something like this:

string name = (context as IObjectContextAdapter).ObjectContext.CreateObjectSet<MyClass>().EntitySet.Name;
Devart
  • 119,203
  • 23
  • 166
  • 186
4

You can try something like this.

private string GetTableName(Type type)
{
  var tableAttribute = type.GetCustomAttributes(false).OfType<System.ComponentModel.DataAnnotations.TableAttribute>().FirstOrDefault();
  return tableAttribute == null ? type.Name : tableAttribute.Name;
}

You can call this string like this.

var tableName = GetTableName(entityType.FirstOrDefault());

Please see the below link for further info. Link

Jethro
  • 5,896
  • 3
  • 23
  • 24
1

I also found that CreateObjectSet() doesn't quite do the job, particularly when getting column names for use in SqlBulCopy(). The following code for getting the EntitySet seems to work better,

 private EntitySet GetEntitySet<T>(DbContext context)
{
    var type = typeof(T);
    var entityName = type.Name;
    var metadata = ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace;

    IEnumerable<EntitySet> entitySets;
    entitySets = metadata.GetItemCollection(DataSpace.SSpace)
                     .GetItems<EntityContainer>()
                     .Single()
                     .BaseEntitySets
                     .OfType<EntitySet>()
                     .Where(s => !s.MetadataProperties.Contains("Type")
                                 || s.MetadataProperties["Type"].ToString() == "Tables");
    var entitySet = entitySets.FirstOrDefault(t => t.Name == entityName);
    return entitySet;
}

To get the table name, there's two other methods I use instead of EntitySet.Name which returns the singular rather than pluralized name.

public string GetTableName<T>(DbContext context)
            where T: class
{
    var entitySet= GetEntitySet<T>(context);
    if (entitySet == null)
        throw new Exception("Unable to find entity set '{0}' in edm metadata".F(typeof(T).Name));
    var tableName = GetStringProperty(entitySet, "Schema") + "." + GetStringProperty(entitySet, "Table");
    return tableName;
}

private string GetStringProperty(MetadataItem entitySet, string propertyName)
{
    MetadataProperty property;
    if (entitySet == null)
        throw new ArgumentNullException("entitySet");
    if (entitySet.MetadataProperties.TryGetValue(propertyName, false, out property))
    {
        string str = null;
        if (((property != null) &&
            (property.Value != null)) &&
            (((str = property.Value as string) != null) &&
            !string.IsNullOrEmpty(str)))
        {
            return str;
        }
    }
    return string.Empty;
}

This returns the actual name used in the database and well as the db schema (in case you're not using dbo), and should work with data annotations or fluent configuration.

The only caveat may be that the database should already be initialized. (which I think is the problem with using CreateObjectSet() - there's a step missing which resolves the db schema).

Tim Abell
  • 11,186
  • 8
  • 79
  • 110
Ackroydd
  • 1,482
  • 1
  • 13
  • 14
-1

Using EF Core

protected virtual string GetTableName()
{
    var entityType = dbContext.Model.FindEntityType(typeof(TEntity));

    //Note: We need Nuget package Microsoft.EntityFrameworkCore.SqlServer
    //var tableName = entityType!.GetSchemaQualifiedTableName();

    var tableName = entityType!.GetTableName();

    return tableName!;
}

Using EF6

Source: https://learn.microsoft.com/en-us/ef/ef6/modeling/code-first/conventions/custom?redirectedfrom=MSDN#configuring-types

using System.Data.Entity;
using System.Data.Entity.Infrastructure.DependencyResolution;
using System.Data.Entity.Infrastructure.Pluralization;

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Types().Configure(c => c.ToTable(GetTableName(c.ClrType)));

    base.OnModelCreating(modelBuilder);
}

private string GetTableName(Type type)
{
    var pluralizationService = DbConfiguration.DependencyResolver.GetService<IPluralizationService>();

    var result = pluralizationService.Pluralize(type.Name);

    result = Regex.Replace(result, ".[A-Z]", m => m.Value[0] + "_" + m.Value[1]);

    return result.ToLower();
}
hpsanampudi
  • 629
  • 6
  • 9
  • 3
    This doesn't use configuration, instead it only assumes default conventions. This doesn't work when overriding the table name manually, when not using the pluralization convention or when using a custom naming convention. – mycroes Dec 08 '20 at 09:31
-1

You can apply extension method to get Table name from your entity class
In this case, You wont need DbContext to get table name , it gets it inside extension method

public static string GetTableName<T>(this T entity) where T : class
{
    var object_context = GetObjectContext(entity);

    if (object_context == null || object_context.TransactionHandler == null)
        return null;

     var dbcontext=object_context.TransactionHandler.DbContext;
    var query= dbcontext.Set(entity.GetType()).ToString();
    var reg = new Regex(@"FROM \[dbo\]\.\[(?<table>.*)\] AS");
    var match = reg.Match(query);

    var tableName= match.Groups["table"].Value;
    return tableName;
}

private static ObjectContext GetObjectContext(object entity)
{
    var field = entity.GetType().GetField("_entityWrapper");

    if (field == null)
        return null;

    var val= field.GetValue(entity);
    var property = val.GetType().GetProperty("Context");
    var context = (ObjectContext)property.GetValue(val, null);

    return context;
}

This is where we reach to DbContext:

var object_context = GetObjectContext(entity)

Usage:

var tableName = entity.GetTableName();
Abolfazl
  • 1,592
  • 11
  • 32