如何在运行时从DbContext获取表名

时间:2011-11-26 02:13:20

标签: entity-framework entity-framework-4 entity-framework-4.1

我试图在运行时从 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.

  • 首先:发生此错误的原因。
  • 第二:有没有办法获得这个SSpcae项目,或表名?

4 个答案:

答案 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行。

按原样运行以下代码:

  1. 创建Windows表单应用
  2. 为Northwind DB添加实体数据模型,将其命名为“NorthwindModel”
  3. 添加两个组合框和一个datagridview(tablesComboBox,topXComboBox和dataGridViewForOutput)
  4. 将项目添加到topXComboBox(全部,前5名,前10名等)(必须是5的倍数才能使代码生效)
  5. 将表单名称更改为mainForm
  6. 突出显示表单文件中的所有代码,并替换为以下
  7. 
    
        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)