Подтвердить что ты не робот

Entity Framework - Получить список таблиц

Что это. Это довольно просто. У меня есть edmx и вы хотите динамически запрашивать его для таблиц и (надеюсь) динамически строить против этой таблицы. Возможно ли это?

=========

UPDATE:

Я включил все таблицы БД, но не просмотрел или SP, в контексте. У нас есть много таблиц, которые вводят информацию (с идентификаторами). Так, например, цвета, тип файла или тип протокола. Я хочу иметь возможность принимать запрос типа (файла) для таблиц, которые могут содержать информацию о типе (File, FileType) и возвращать его с идентификатором.

Итак, я могу найти... Бизнес-блок (или цвет или файл), и код исчезнет и будет искать контекст для BusinessUnit (или цвета или файла) и BusinessUnitType (или ColorType или FileType). Если он найдет один, он запросит его и вернет все строки, чтобы я мог видеть, содержит ли это информацию о типе (я уточню его позже, чтобы возвращать только идентификаторы и описания, аббревиатуру или поля имени, а также ограничивающие строки и т.д.). и иметь возможность найти связанный идентификатор для конкретного.

4b9b3361

Ответ 1

Для вашего первого вопроса о том, как перечислять таблицы в базе данных, этот код получит их для вас, конечно, те, которые были импортированы в ваш 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();

Вы можете прочитать больше здесь: Быстрый трюк для принудительной загрузки метаданных в ApplicationCollections

Однако, если вы хотите создать динамический запрос против таблиц типов, вам не нужно обходиться с помощью 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;
    }
}


Код Объяснение: Мое предположение заключалось в том, что имена ваших типов таблиц заканчиваются в "Тип" как постфикс (например, ColorType), поэтому вы можете вызвать GetAllType ( "Цвет" ), и он ищет ColorType EntityObject в вашей модели и предоставит вам все возможные значения. Код может выглядеть страшно, но это довольно простой материал. В основном все, что он делает, это то, что он получает всю необходимую информацию из MetaData (например, имя EntitySet, имя пространства имен и т.д.) На основе параметра метода, а затем создает запрос EntitySQL "на лету", затем выполняет его и возвращает Результаты.

Ответ 2

Этот пример кода из сообщения Какие таблицы в моей модели EF? И моя база данных?

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

Ответ 3

На всякий случай это помогает, я вытащил их из одного из моих классов 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.

Я не уверен, что вы делаете, поэтому может быть лучший способ сделать это... как только вы обновите свою конечную цель, я отредактирую ее соответствующим образом.