实体框架 - 获取表列表

时间:2010-10-08 17:35:40

标签: entity-framework

就是这样。这很简单。我有一个edmx,并希​​望能够动态地查询表和(希望)动态构建该表。这可能吗?

======

更新:

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

因此,我可能会寻找...业务单位(或颜色或文件),代码将关闭并搜索BusinessUnit(或Color或File)和BusinessUnitType(或ColorType或FileType)的上下文。如果它找到任何一个,它将查询它并将返回所有行,以便我可以看到它是否包含类型信息(我稍后将其细化为仅返回ID和描述,缩写或名称字段以及限制行等)并且能够找到特定任何内容的相关ID。

3 个答案:

答案 0 :(得分:16)

关于如何枚举数据库中的表的第一个问题,这段代码将为您提供这些代码,当然还有导入到您的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并将给你所有可能的价值。代码可能看起来很吓人,但这很简单。基本上它所做的就是它根据方法参数从MetaData获取所有必需的信息(如EntitySet名称,命名空间名称等),然后动态构建一个EntitySQL查询,然后执行它并返回结果。

答案 1 :(得分:15)

来自帖子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);
    }
}

答案 2 :(得分:2)

为了防止这种情况发生,我从我的一个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。

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