我试图在运行时从 DbContext 获取数据库表名,我发现posts在EF 4.x中无法获得 SSpace 项目(以及表格名称)默认情况下还没有针对这些操作的公共API。
但我尝试对此进行一些测试,并且我能够在运行时使用调试器从 DbContext 获取表名
此语法由Visual Studio生成
((System.Data.Entity.DbContext)(context)).System.Data.Entity.Infrastructure.IObjectContextAdapter.ObjectContext.MetadataWorkspace._itemsSSpace
我做了一些修改,使其在代码中可用,并屈服于此
var objContext = (context as IObjectContextAdapter).ObjectContext;
var metaData = objContext.MetadataWorkspace;
var items = metaData.GetItems(DataSpace.SSpace);
虽然它遵循相同的目标,但items
抛出异常The space 'SSpace' has no associated collection.
答案 0 :(得分:4)
这是运行时的一种方式。
public static List<string> GetTableNames()
{
List<string> tableNameList = new List<string>();
// use DBContext to get ObjectContext
DatabaseContext db = new DatabaseContext();
IObjectContextAdapter adapter = db as IObjectContextAdapter;
System.Data.Objects.ObjectContext objectContext = adapter.ObjectContext;
ReadOnlyCollection<EntityType> allTypes = objectContext.MetadataWorkspace.GetItems<EntityType>(DataSpace.CSpace);
foreach (EntityType item in allTypes)
{
// Create full assembly name
string typeName = "original.poco.namespace." + item.Name;
Type type = Type.GetType(typeName);
// wrap into a function
string sql = db.Set(type).ToString();
Regex regex = new Regex(@"FROM \[dbo\]\.\[(?<table>.*)\] AS");
Match match = regex.Match(sql);
tableNameList.Add( match.Groups["table"].Value);
}
return tableNameList;
}
答案 1 :(得分:2)
您收到该错误,因为在您执行某些操作(执行查询)以使EF需要商店集合之前,商店集合不会被填充。但即使你拥有它,也没有任何好处。您可以通过这种方式获取表名列表,但是实体的映射位于CSSpace项集合中,这是完全不可访问的,因为它使用EF运行时内部的类型。如果你有实体A和B,以及表C和D,即使你知道你有直接的一对一映射,你也无法找到A是映射到C还是映射到D.
答案 2 :(得分:1)
我正在各处使用这些课程;应该证明有用。使用EF4或5.要使ObjectContext从DbContext传递到顶级EntityNavigationList.List,请使用((IObjectContextAdapter)myDbContext).ObjectContext。简单的表名列表将是EntityNavigationList.List中每个项的FromEntity。
public class NavigationItem
{
public string FromEntity { get; set; }
public string ToEntity { get; set; }
public RelationshipMultiplicity FromMultiplicity { get; set; }
public RelationshipMultiplicity ToMultiplicity { get; set; }
public string ForeignKeyColumn { get; set; }
public string PrimaryKeyColumn { get; set; }
public EntitySetBase EntitySet { get; set; }
/// <summary>
/// Entity type may be "Formula"; entity set may be "Formulae"
/// </summary>
public string EntitySetName { get { return EntitySet == null ? string.Empty : EntitySet.Name; } }
}
public static class EntityNavigationList
{
private static List<NavigationItem> _navItems;
public static List<NavigationItem> List( ObjectContext context )
{
if ( _navItems == null )
{
InitializeNavigationItems( context );
}
return _navItems;
}
/// <summary>
/// Create a list of all navigation items in the model
/// </summary>
private static void InitializeNavigationItems( ObjectContext context )
{
var entityMetadata = context.MetadataWorkspace.GetItems( DataSpace.CSpace );
var entitySetMetadata = context.MetadataWorkspace.GetEntityContainer( context.DefaultContainerName, DataSpace.CSpace ).BaseEntitySets;
var query = from meta in entityMetadata
.Where( m => m.BuiltInTypeKind == BuiltInTypeKind.EntityType )
from p in ( meta as EntityType ).NavigationProperties
let foreignKey = ( p.ToEndMember.DeclaringType as AssociationType ).ReferentialConstraints.FirstOrDefault()
let primaryKey = ( meta as EntityType ).KeyMembers
select new NavigationItem
{
FromEntity = p.FromEndMember.Name,
ToEntity = p.ToEndMember.Name,
FromMultiplicity = p.FromEndMember.RelationshipMultiplicity,
ToMultiplicity = p.ToEndMember.RelationshipMultiplicity,
ForeignKeyColumn = foreignKey == null ? string.Empty : foreignKey.ToProperties.First().ToString(),
PrimaryKeyColumn = primaryKey == null ? string.Empty : primaryKey.First().Name,
/// We need the corresponding entity set so we can get it's name (formula belongs to entity set "formulae")
EntitySet = ( from moMeta in entitySetMetadata
where moMeta.ElementType.Name == p.FromEndMember.Name
select moMeta ).FirstOrDefault()
};
_navItems = query.ToList();
}
}
答案 3 :(得分:1)
以下是今天针对Microsoft的Northwind示例数据库开发的一些代码,演示了如何从实体数据模型中获取表列表,然后显示DataGridView中所选表的前x行。
按原样运行以下代码:
using System;
using System.Data.Entity;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
namespace EntityFrameworkBrowser
{
public partial class mainForm : Form
{
public mainForm()
{
InitializeComponent();
}
private void mainForm_Load(object sender, EventArgs e)
{
Type type = typeof(NorthwindModelEntities);
var query = type.GetProperties().Where(p => p.GetMethod.ToString().ToLower().Contains(".dbset")).Select(m => m.Name);
tablesComboBox.DataSource = query.ToList();
topXComboBox.SelectedIndex = 1;
}
private async void BindTableData()
{
// Ensure the form has been initialised
if (topXComboBox.SelectedIndex.Equals(-1))
{
return;
}
// Get the DB context
NorthwindModelEntities dbContext = new NorthwindModelEntities();
// Get a reference to the type of the model
Type type = typeof(NorthwindModelEntities);
// Get the table name selected by the user in the combo box
string tableName = tablesComboBox.SelectedItem.ToString();
// Get a reference to the DbSet from the model
var prop = type.GetProperty(tableName);
// Get a reference to the getter for the DbSet
MethodInfo get = prop.GetMethod;
// Invoke the getter for the DbSet
object tableContent = get.Invoke(dbContext, null);
// Create a query that will return all records from the selected table
IQueryable query = (IQueryable)tableContent;
// Find out how many records the user has requested, All, Top5, Top 10, etc
int count = topXComboBox.SelectedIndex * 5;
// If a value other than all (selected index 0) has been selected the query needs to be refactored
if (count != 0)
{
// Get the element type for the DbSet from the entity data model
Type returnType = query.ElementType;
// Get a reference to the 'Take' extension method
MethodInfo takeMethod = (MethodInfo)typeof(Queryable).GetMethod("Take");
// Make a generic version of the 'Take' method
MethodInfo m = takeMethod.MakeGenericMethod(returnType);
// Refactor the query to take the top X records based on the user combo box selection
query = (IQueryable)m.Invoke(null, new object[] { query, count });
}
// Execute the query and bind the results to the data grid view
dataGridViewForOutput.DataSource = await query.ToListAsync();
}
private void tablesComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
BindTableData();
}
private void topXComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
BindTableData();
}
}
}
希望评论能够解释发生了什么,你不会猜到它。
希望它有所帮助,因为它花了一些时间
:0)