Как получить имя таблицы из DbContext во время выполнения - PullRequest
2 голосов
/ 26 ноября 2011

Я пытаюсь получить имя таблицы базы данных из 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 ]

4 голосов
/ 17 апреля 2012

Это один из способов во время выполнения.

        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 голосов
/ 26 ноября 2011

Вы получаете эту ошибку, потому что коллекция хранилища не будет заполнена, пока вы не сделаете что-то (выполните запрос), чтобы EF потребовал коллекцию хранилища. Но даже если он у вас есть, он вам не поможет. Вы можете получить список имен таблиц таким образом, но отображение ваших сущностей находится в коллекции элементов CSSpace, которая полностью недоступна, поскольку использует типы, внутренние для среды выполнения EF. Если у вас есть объекты A и B, а также таблицы C и D, даже если вы знаете, что у вас прямое сопоставление «один к одному», вы не сможете найти, сопоставлен ли A с C или D.

1 голос
/ 11 ноября 2013

Вот код, разработанный сегодня для образца базы данных Northwind от Microsoft, который демонстрирует, как получить список таблиц из модели данных объекта, а затем отобразить верхние x строк из таблицы, выбранной в DataGridView.

Чтобы запустить приведенный ниже код следующим образом:

  1. Создайте приложение для форм Windows
  2. Добавьте модель данных сущности для БД Northwind, назовите ее 'NorthwindModel'
  3. Добавьте два поля со списком и представление таблицы данных (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();
            }
        }
    }

Надеемся, что комментарии должны объяснить, что происходит, вы не могли быне угадаю.

Надеюсь, это кому-нибудь поможет, так как потребовалось немного потренироваться

: 0)

1 голос
/ 30 августа 2013

Я использую эти классы повсюду;должно оказаться полезным.Работает с EF4 или 5. Чтобы получить ObjectContext для передачи в EntityNavigationList.List верхнего уровня из DbContext, используйте ((IObjectContextAdapter) myDbContext) .ObjectContext.Простым списком имен таблиц будет FromEntity каждого элемента в EntityNavigationList.List.

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

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...