【问题标题】:Entity Framework - Get List of Tables实体框架 - 获取表列表
【发布时间】:2016-02-10 20:34:00
【问题描述】:

就是这样。这很简单。我有一个 edmx 并且希望能够动态地查询它以获取表,并且(希望)动态地针对该表进行构建。这可能吗?

=========

更新:

我在上下文中包含了所有数据库表,但没有视图或 SP。我们有很多类型信息(带有 id)的表。因此,例如,颜色或文件类型或协议类型。我希望能够对可能包含类型信息(文件、文件类型)的表进行类型(文件)查询并返回它的 id。

所以,我可能会寻找... Business Unit(或 Color,或 File),然后代码会开始搜索 BusinessUnit(或 Color 或 File)和 BusinessUnitType(或 ColorType 或 FileType)的上下文。如果找到任何一个,它将查询它并返回所有行,以便我可以查看它是否包含类型信息(稍后我将对其进行细化以仅返回 ID 和描述、缩写或名称字段以及限制行等)并能够找到特定事物的关联 ID。

【问题讨论】:

  • 表格或实体?抽象的还是具体的?名称或类型?为什么?请具体。
  • 表格 - 就是这样。只是桌子。通过在 SQL Server 中查询 sysobjects 得到的东西。
  • 您想要在您的上下文中还是在数据库中使用表?
  • @Nix - 在数据库中,通过上下文,但我不得不承认我是 EF 的新手,不知道为什么会有差异
  • 您的上下文不必包含数据库中的所有内容,您可以对表的子集进行建模...您能否提供更多关于您计划如何动态查询数据的信息?因为可以从上下文中获取所有表/对象查询。

标签: entity-framework


【解决方案1】:

此示例代码来自帖子What Tables Are In My EF Model? And My Database?

using (var dbContext = new YourDbContext())
{
    var metadata = ((IObjectContextAdapter)dbContext).ObjectContext.MetadataWorkspace;

    var tables = metadata.GetItemCollection(DataSpace.SSpace)
        .GetItems<EntityContainer>()
        .Single()
        .BaseEntitySets
        .OfType<EntitySet>()
        .Where(s => !s.MetadataProperties.Contains("Type")
        || s.MetadataProperties["Type"].ToString() == "Tables");

    foreach (var table in tables)
    {
        var tableName = table.MetadataProperties.Contains("Table")
            && table.MetadataProperties["Table"].Value != null
            ? table.MetadataProperties["Table"].Value.ToString()
            : table.Name;

        var tableSchema = table.MetadataProperties["Schema"].Value.ToString();

        Console.WriteLine(tableSchema + "." + tableName);
    }
}

【讨论】:

  • 这绝对是最好的解决方案
  • ... 如果要列出表/实体的属性/字段,可以查询表对象: var PropertiesInTables = tables.Select(s => s.ElementType.Properties) .ToList();
【解决方案2】:

对于如何枚举数据库中的表的第一个问题,此代码将为您获取它们,当然,已导入 EDM 的那些不一定是数据存储中的所有表。

var tableNames = context.MetadataWorkspace.GetItems(DataSpace.SSpace)
                        .Select(t => t.Name)
                        .ToList();

此代码将导致带有以下消息的 InvalidOperationException:
空间“SSpace”没有关联的集合
这是因为与 CSpace 不同,SSpace (ssdl) 在需要时才会加载。并尝试使用 MetadataWorkspace 读取它们不算是需要的。在查询编译期间需要它,然后在对象实现时再次需要它。因此,为了欺骗 MetadataWorkspace 为我们加载它,我们需要在运行为我们提供表名的主查询之前运行如下所示的查询。

string temp = ((ObjectQuery)context.[EntitySetName]).ToTraceString();

您可以从这里阅读更多内容:Quick Trick for forcing MetadataWorkspace ItemCollections to load

但是,如果您的意图是针对您的类型表构建一个动态查询,那么您不需要搞乱 SSpace,您必须从 CSpace(概念模型)中获取它。下面是一个示例代码,关于如何构建一个只有部分表名的动态查询:

ObjectResult<DbDataRecord> GetAllTypes(string name) {
    using (TypeEntities context = new TypeEntities()) {

    MetadataWorkspace metadataWorkspace = context.MetadataWorkspace;
    EntityContainer container = metadataWorkspace.GetItems<EntityContainer>
                                                      (DataSpace.CSpace).First();
    string namespaceName = metadataWorkspace.GetItems<EntityType>
                                        (DataSpace.CSpace).First().NamespaceName;

    string setName = string.Empty;
    string entityName = name + "Type";

    EntitySetBase entitySetBase = container.BaseEntitySets
            .FirstOrDefault(set => set.ElementType.Name == entityName);

    if (entitySetBase != null) {
        setName = entitySetBase.Name;
    }
    EntityType entityType = metadataWorkspace
         .GetItem<EntityType>(namespaceName + "." + entityName, DataSpace.CSpace);

    StringBuilder stringBuilder = new StringBuilder().Append("SELECT entity ");
    stringBuilder
       .Append(" FROM " + container.Name.Trim() + "." + setName + " AS entity ");
    string eSQL = stringBuilder.ToString();

    ObjectQuery<DbDataRecord> query = context.CreateQuery(eSQL);
    ObjectResult<DbDataRecord> results = query.Execute(MergeOption.AppendOnly);
    return results;
    }
}


代码说明: 我的假设是您的类型表名称以“Type”结尾作为后缀(例如 ColorType),因此您可以调用 GetAllType("Color") 并在您的模型中搜索 ColorType EntityObject 并将给你所有可能的值。代码可能看起来很吓人,但它非常简单。基本上,它所做的只是根据方法参数从元数据(如实体集名称、命名空间名称等)中获取所有必需的信息,然后动态构建一个 EntitySQL 查询,然后执行它并返回结果。

【讨论】:

  • 上述代码的EF版本是什么?我在 EF4.0 中尝试过,“t => t.Name”甚至无法编译。有什么解决办法吗?
  • 我使用的是 EF 6.1.1,这段代码对我有用 List tableList = db.MetadataWorkspace.GetItems(DataSpace.CSpace).Select(x => x.Name) ;
  • 我有同样的@LeiYang 问题修复: var items = objectContext.MetadataWorkspace.GetItems(DataSpace.SSpace);
【解决方案3】:

以防万一,我从我的一个 ObjectContextExtension 类中提取了这些。

您可以查询您的对象上下文并获取如下名称。您可以随意修改。

public static class ObjectContextExtensions
{
    public static string GetEntitySetName<T>(this ObjectContext theContext, T eo) where T : EntityObject
    {
        string entitySetName = "";
        if (eo.EntityKey != null)
        {
            entitySetName = eo.EntityKey.EntitySetName;
        }
        else
        {
            string className = typeof(T).Name;
            var container =
                   theContext.MetadataWorkspace.GetEntityContainer(theContext.DefaultContainerName, DataSpace.CSpace);
            entitySetName = (from meta in container.BaseEntitySets
                             where meta.ElementType.Name == className
                             select meta.Name
                            ).First();

        }

        return entitySetName;
    }
    public static IEnumerable<EntitySetBase> GetEntitySets(this ObjectContext theContext) 
    {
            var container =
                   theContext.MetadataWorkspace
                      .GetEntityContainer(
                            theContext.DefaultContainerName,
                            DataSpace.CSpace);

            return container.BaseEntitySets;
    }
    public static IEnumerable<ObjectQuery> GetObjectQueries(this ObjectContext theContext) 
    {
        IEnumerable<ObjectQuery> queries =
              from pd in theContext
                           .GetType()
                           .GetProperties()
              where pd.PropertyType
                       .IsSubclassOf(typeof(ObjectQuery))
              select (ObjectQuery)pd.GetValue(theContext, null);
        return queries;
    }
}

当你使用它时:

IEnumerable<EntitySetBase> lookAtMe = context.GetEntitySets();
//ElementType (type of entity the set represents)
//Entity Set Name
//Other fun goodies ;)

//Example of how to get the entity set to query on it.
File f = new File();
//or some entity you selected.
f = context.Files.FirstOrDefault();
string name = context.GetEntitySetName(f);

我遗漏的另一个是 GetObjectQueries,它只返回所有 ObjectQueries,它们是您查询的上下文中的内容。 context.SomeTable 或 context.Products。

我不确定你在做什么,所以可能有更好的方法来做到这一点......一旦你更新了你的最终目标,我会相应地进行编辑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多