【问题标题】:How to get the Schema name of a Table in Entity Framework?如何在实体框架中获取表的架构名称?
【发布时间】:2012-02-04 21:50:14
【问题描述】:

我使用用户模式分离技术来分离数据库中的表。你能告诉我如何在实体框架中获取实体集(表)的模式名称吗?谢谢。

【问题讨论】:

  • @LadislavMrnka,我们的客户将表分成不同的模式。有一个审计跟踪功能可以记录表的每次更改。我想添加一列来标识该表属于哪个架构,并且可以在 SELECT 时过滤审计跟踪记录。

标签: c# entity-framework schema entity


【解决方案1】:

现在这一定是一个老话题了,但是对于那些仍然潜伏在 EF6+ 中(而不是 EF 核心)的人,基于过去 Rowan Miller 的同样出色的博客 post,请查看我的方法显示有关给定实体的一些元信息

public class DbTableMeta
{
    public string Schema { get; set; }

    public string Name { get; set; }

    public IEnumerable<string> Keys { get; set; }
}


public static DbTableMeta Meta(this DbContext context, Type type)
{
    var metadata = ((IObjectContextAdapter) context).ObjectContext.MetadataWorkspace;

    // Get the part of the model that contains info about the actual CLR types
    var items = (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(p => items.GetClrType(p) == type);

    // Get the entity set that uses this entity type
    var entitySet = metadata
        .GetItems<EntityContainer>(DataSpace.CSpace)
        .Single()
        .EntitySets
        .Single(p => p.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(p => p.EntitySet == entitySet);

    // Find the storage entity set (table) that the entity is mapped
    var table = mapping
        .EntityTypeMappings.Single()
        .Fragments.Single()
        .StoreEntitySet;

    return new DbTableMeta
    {
        Schema = (string) table.MetadataProperties["Schema"].Value ?? table.Schema,
        Name = (string) table.MetadataProperties["Table"].Value ?? table.Name,
        Keys = entityType.KeyMembers.Select(p => p.Name),
    };
}

【讨论】:

    【解决方案2】:

    DbContextObjectContext 的扩展方法:

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

    使用 ObjectContext 对象:

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

    使用 DbContext 对象:

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

    更多信息在这里:

    Entity Framework: Get mapped table name from an entity

    【讨论】:

    • 我不会反对你,但使用 LINQ to SQL 和正则表达式似乎是获取表名的糟糕方法。
    • @RuudLenders 请记住,我的答案是 6 岁!我很长时间没有使用 EF - 我很确定从 2018 年开始更容易访问元数据,但在 2012 年情况就大不相同了 :-)
    【解决方案3】:

    我发现以下博客条目解释了如何从元数据工作区获取该信息:

    https://romiller.com/2014/04/08/ef6-1-mapping-between-types-tables/

    这是发挥神奇作用的函数:

    public static string GetTableName(Type type, 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) == 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;
    }
    

    【讨论】:

    • Dan Dohotaru 一年前发布了这个答案,但这得到了更多的支持?
    • @RuudLenders 嗯,这确实很奇怪。一年后我真的发布了几乎相同的答案吗?奇怪。
    • Dan 在将近一年后发布,而不是一年前。
    【解决方案4】:

    对于那些使用代码优先的人,架构名称在您的上下文的 OnModelCreating 覆盖中设置;

    public static readonly string DefaultSchemaName = "Entities";
    
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema(DefaultSchemaName);
    
        ...
    

    所以您应该能够在代码中的其他地方引用DefaultSchemaName

    如果您一开始没有构建模型上下文和 EF 内容,那么这个答案就不太明显了。

    【讨论】:

      【解决方案5】:

      用于截断需要表名和架构的表的示例。

      public void ClearTable<T>() where  T: class
          {
              var dbContext = (DbContext) _dbContext;
              
              var annotations = dbContext.Model.FindEntityType(typeof(T)).GetAnnotations().ToList();
      
              var tableName = annotations.First(c => c.Name == "Relational:TableName").Value.ToString();
              var schema = annotations.First(c => c.Name == "Relational:Schema").Value.ToString();
      
              dbContext.Database.ExecuteSqlRaw($"truncate table {schema}.{tableName}");
      
          }
      

      【讨论】:

        【解决方案6】:

        使用 Entity Framework 6.1.3 您可以通过以下方式查询方案和表名:

          string tableNameWithScheme = context.Db<T>().Schema+"."+context.Db<T>().TableName;
        

        其中 T 是实体的类型,上下文是派生的 System.Data.Entity.DBContext 的实例。

        【讨论】:

        • 你确定吗?我认为Db&lt;T&gt; 不存在。
        • 是的,我完全确定在使用 MSSql 的情况下!啊,当然 T 是你的函数的参数!
        • 那么Db函数here在哪里?没有这样的事情。
        猜你喜欢
        • 2013-10-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-28
        • 1970-01-01
        • 1970-01-01
        • 2013-08-23
        相关资源
        最近更新 更多