可能吗?我知道当我指定 TableAttribute 时我可以获取名称,但即使如此,当我让框架管理名称时,也应该是可能的。
提前谢谢。
我最终得到了这个:
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 表名。
的正确方法是使用以下页面中的 GetTableName
方法:http://romiller.com/2014/04/08/ef6-1-mapping-between-types-tables/
这包括对元标记和模型生成器.ToTable()
更改的支持。此页面上的示例基本上返回DbSet
属性名称,该属性名称不一定是数据库中的表名称。
例如,如果您有:
DbSet<Config> Settings { get; set; }
当实际数据库表名称为"配置"时,此页面上的代码将返回表名称的"设置"。如果您使用,您将遇到相同的问题:
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;
}
}
如果不使用 TableAttribute
或流畅的 api 来定义表名,则名称将从上下文中DbSet
属性的名称推断出来。在这种情况下,唯一可以修改名称的是默认使用的复数约定。
因此,如果您有:
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
}
该表应命名为 Users
。
这应该处理每个类型的表和每个层次结构的表继承。
看: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;
}