就是这样。这很简单。我有一个edmx,并希望能够动态地查询表和(希望)动态构建该表。这可能吗?
======
更新:
我在上下文中包含了所有数据库表,但没有包含视图或SP。我们有很多类型信息的表(带有id)。因此,例如,颜色或文件类型或协议类型。我希望能够对可能包含类型信息(File,FileType)的表进行类型(文件)查询,并将其返回id。
因此,我可能会寻找...业务单位(或颜色或文件),代码将关闭并搜索BusinessUnit(或Color或File)和BusinessUnitType(或ColorType或FileType)的上下文。如果它找到任何一个,它将查询它并将返回所有行,以便我可以看到它是否包含类型信息(我稍后将其细化为仅返回ID和描述,缩写或名称字段以及限制行等)并且能够找到特定任何内容的相关ID。
答案 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。
我不确定你在做什么,所以可能有更好的方法来做到这一点....一旦你更新你的最终目标,我会相应地进行编辑。