实体框架|代码优先 - 获取创建表的名称

时间:2011-05-10 11:56:28

标签: entity-framework entity-framework-4 entity-framework-4.1 code-first

有可能吗?当我指定TableAttribute时,我知道我可以获得名称,但是当我让框架管理名称时,它应该是可能的。

提前致谢。

4 个答案:

答案 0 :(得分:11)

我最终得到了这个:

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;
    }
}

这是两个答案的混合:DBset tabel name

答案 1 :(得分:4)

执行此操作的正确方法是使用以下页面中的GetTableName方法:http://romiller.com/2014/04/08/ef6-1-mapping-between-types-tables/

这包括对元标记和模型构建器.ToTable()更改的支持。此页面上的示例基本上返回DbSet属性名称,该名称不一定是数据库中的表名。

例如,如果你有:

DbSet<Config> Settings { get; set; }

当实际数据库表名称为“Configs”时,此页面上的代码将返回表名称的“设置”。如果使用的话,你会遇到同样的问题:

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

使用提供的链接中的代码可以缓解所有这些问题。这里写的是扩展名:

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;
    }
}

答案 2 :(得分:2)

如果您不使用TableAttribute或流畅的api来定义表名,则将从上下文中DbSet属性的名称推断出该名称。在这种情况下唯一可以修改名称的是默认使用的复数约定。

所以如果你有:

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

该表应命名为Users

答案 3 :(得分:1)

这应该处理每个类型的表和每个层次结构继承的表。

请参阅: 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

诀窍是遍历继承树,直到找到覆盖的Table属性或非对象基类型。如果可能从未映射到表的类继承,这可能会失败...我不确定。如果你可以对类进行[NotMapped],那么在这种情况下我们只需改变GetTableDefType方法就可以向后移动一次。

   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;
    }