开发者

Entity Framework | Code First - Get Name Of Created Table

Is it possible? I know I can get the name, when I've specified the TableAttribute, but it should be possible even so, when I 开发者_Go百科let the framework manage the name.

Thanks in advance.


I ended up with this:

public static class DbContextExt
{
    public static string GetTableName<T>(this DbContext context) where T : class
    {
        var type = typeof(T);
        var entityName = (context as System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext.CreateObjectSet<T>().EntitySet.Name;
        var tableAttribute = type.GetCustomAttributes(false).OfType<System.ComponentModel.DataAnnotations.Schema.TableAttribute>().FirstOrDefault();

        return tableAttribute == null ? entityName : tableAttribute.Name;
    }
}

It's a hybrid of the two answers here: DBset tabel name.


The proper way to do this is to use the GetTableName method from the following page: http://romiller.com/2014/04/08/ef6-1-mapping-between-types-tables/

This includes support for the meta tag and model builder .ToTable() changes. The examples on this page basically return the DbSet property name which is not necessarily the table name in the database.

For example if you had:

DbSet<Config> Settings { get; set; }

The code on this page would return "Settings" for a table name when the actual DB table name is "Configs". And you would have the same issues if you used:

modelBuilder.Entity<Config>().ToTable("UserSettings")

Using the code in the provided link alleviates all of these issues. Here it is written as an extension:

public static class DbContextExtensions
{
    public static string GetTableName<T>(this DbContext context) where T : class
    {
        var type = typeof(T);
        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 table = mapping
            .EntityTypeMappings.Single()
            .Fragments.Single()
            .StoreEntitySet;

        // Return the table name from the storage entity set
        return (string)table.MetadataProperties["Table"].Value ?? table.Name;
    }
}


If you don't use TableAttribute or fluent api to define the table name, the name will be inferred from the name of DbSet property in the context. The only thing which can modify the name in such case is pluralization convention which is used by default.

So if you have:

public class Context : DbContext
{
    public DbSet<User> Users { get; set; }
}

The table should be named Users.


This should handle Table per Type and Table per Hierarchy inheritance.

See: http://weblogs.asp.net/manavi/archive/2010/12/24/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table-per-hierarchy-tph.aspx

The trick is to walk the inheritance tree until you find an overriden Table attribute or a non-object base type. This could potentially fail if its possible to inherit from a class that's not mapped to a table...which I'm not sure about. If you can do [NotMapped] on a class, then we'd just have to alter the GetTableDefType method to walk backwards once in that case.

   private static Type GetTableDefType(this Type t, out TableAttribute attr) {
        attr = null;
        if (t == typeof(Object)) { throw new ArgumentException(); }
        var tType = t;
        while (true) {               
            attr = tType.GetCustomAttributes(false).OfType<TableAttribute>().FirstOrDefault();
            if (attr != null) { return tType; }

            if (tType.BaseType == null || tType.BaseType == typeof(Object)) { return tType; }
            tType = tType.BaseType;
        }
    }
    public static string GetTableName(this DbContext context, Type type)  {
        TableAttribute testAttr = null;
        var baseType = type.GetTableDefType(out testAttr);

        if (testAttr != null) { return testAttr.TableName; }

        var propBinding = BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty;
        var objectContext = context.GetType().GetInterface("System.Data.Entity.Infrastructure.IObjectContextAdapter").GetProperty("ObjectContext", propBinding).GetValue(context, null);
        var objectSet = objectContext.GetType().GetMethod("CreateObjectSet", new Type[0]).MakeGenericMethod(baseType).Invoke(objectContext, null);
        return ((EntitySet)objectSet.GetType().GetProperty("EntitySet", propBinding).GetValue(objectSet, null)).Name;
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜