【问题标题】:How to get table name from DbContext at runtime如何在运行时从 DbContext 获取表名
【发布时间】:2011-11-26 02:13:20
【问题描述】:

我试图在运行时从 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项,或者表名??

【问题讨论】:

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


【解决方案1】:

这是运行时的一种方式。

        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;
    }

【讨论】:

    【解决方案2】:

    您会收到该错误,因为在您执行某些操作(执行查询)以使 EF 需要存储集合之前,不会填充存储集合。但即使你拥有它,它对你也没有好处。您可以通过这种方式获取表名列表,但到实体的映射位于 CSSpace 项目集合中,这是完全不可访问的,因为它使用 EF 运行时内部的类型。如果您有实体 A 和 B 以及表 C 和 D,即使您知道您有直接的一对一映射,您也无法确定 A 是映射到 C 还是映射到 D。

    【讨论】:

      【解决方案3】:

      这是今天为 Microsoft 的 Northwind 示例数据库开发的一些代码,演示了如何从实体数据模型中获取表列表,然后显示在 DataGridView 中选择的表中的前 x 行。

      按原样运行以下代码:

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

      希望 cmets 应该解释发生了什么,你不会猜到的。

      希望它对某人有所帮助,因为它需要一些锻炼

      :0)

      【讨论】:

        【解决方案4】:

        我到处都在使用这些类;应该证明是有帮助的。与 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();
            }
        
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-04-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-17
          • 1970-01-01
          相关资源
          最近更新 更多