Как динамически добавлять / удалять поля, используя Entity Framework во время выполнения? - PullRequest
2 голосов
/ 03 января 2012

В моем проекте есть требование динамически добавлять / удалять поля во время выполнения.Я уже создал эту функцию, но не в EF.Я хочу создать эту функцию с помощью EF.Есть идеи, как это сделать?

Ответы [ 3 ]

3 голосов
/ 03 января 2012

Если вам нужна динамическая структура данных, вы должны либо использовать совершенно другую архитектуру, либо вы не можете использовать EF.EF не является инструментом для динамического изменения баз данных - просто посмотрите, как вы работаете с EF.Вы сопоставляете статическую таблицу со статическим определением класса.Если вы меняете таблицу во время выполнения, как вы изменяете класс (нет поддержки dynamic в EF)?

В качестве примера альтернативной структуры базы данных вы можете использовать любую базу данных с несколькими предварительно определенными столбцами разных типов, и новые поля будут сопоставлены с новыми типами.В вашем приложении будет дополнительный слой «отображения», который будет интерпретировать содержимое вашей базы данных на основе метаданных определенного типа, хранящихся в другом месте.Этот подход используется, например, в Sharepoint (по крайней мере в 2007 году), когда вы отдельно сохранили тип контента (описание данных), но весь контент находится в одной огромной таблице с большим количеством столбцов.

Другой пример - структура, в которой выиметь отдельную таблицу для основных данных (совместно используемых всеми сущностями), отдельную таблицу для описания свойств и отдельную таблицу для значений свойств, связанных с основными данными.Эта структура базы данных имеет имя, но я не могу вспомнить его в данный момент.

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

Ваш связанный инструмент не предназначен для изменения структуры базы данных.Это просто для изменения имен в отображении, но структура таблицы должна оставаться прежней.

2 голосов
/ 09 октября 2015

Это вербатин, взятый из блога Роуэн Миллер.

http://romiller.com/2012/03/26/dynamically-building-a-model-with-code-first/.

Еще нужно изменить, чтобы свойства классов читались из какого-либо источника конфигурации илииз полей таблицы базы данных.


Динамическое построение модели с первым кодом Опубликовано 26 марта 2012 г.

Я ответил на несколько писемнедавно по этой теме, поэтому пришло время превратить его в сообщение в блоге.

В этом сценарии набор классов, составляющих вашу модель, неизвестен во время компиляции и обнаруживается динамически во время выполнения.Примером такого сценария является WordPress / Orchard / и т. Д.веб-сайт стиля, позволяющий подключать модули. Эти модули находятся в отдельной сборке и могут содержать классы, представляющие данные, которые необходимо сохранить в базе данных приложения.Все эти классы включены в центральную модель Code First, которая будет использоваться для доступа к данным.

Поиск классов Существует множество различных подходов для определения классов, которые будут включены в модель.Для этого примера давайте используем атрибут [Persistent], что-то вроде этого:

[AttributeUsage (AttributeTargets.Class)] открытый класс PersistentAttribute: Attribute {} Теперь мы можем добавить некоторую логику в метод OnModelCreating нашего контекстасканировать сборки и добавлять любые классы с атрибутом [Persist].Мы собираемся предположить, что сборки, которые могут содержать классы, все загружены в текущий AppDomain, конечно, у вас может быть какой-то другой механизм, который предоставляет список сборок для проверки.

public class MyContext : DbContext
{
  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
    var entityMethod = typeof(DbModelBuilder).GetMethod("Entity");

    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
      var entityTypes = assembly
        .GetTypes()
        .Where(t =>
          t.GetCustomAttributes(typeof(PersistentAttribute), inherit: true)
          .Any());

      foreach (var type in entityTypes)
      {
        entityMethod.MakeGenericMethod(type)
          .Invoke(modelBuilder, new object[] { });
      }
    }
  }
}

В этомНапример, вся модель обнаруживается динамически, но вы также можете иметь некоторые статические части модели, которые также зарегистрированы в modelBuilder.

Альтернатива, использующая код EntityConfiguration First, позволяет вам создать класс, производный от EntityTypeConfiguration, для инкапсуляцииконфигурация Fluent API для объекта.Если вы используете этот подход к конфигурации, вы можете просто искать эти классы конфигурации и регистрировать их, вместо того, чтобы находить объекты для регистрации.Обратите внимание, что мы отфильтровываем сборку EntityFramework, поскольку у нее есть некоторые классы конфигурации, которые она использует для внутреннего использования.

public class MyContext : DbContext
{
  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
    var addMethod = typeof(ConfigurationRegistrar)
      .GetMethods()
      .Single(m => 
        m.Name == "Add" 
        && m.GetGenericArguments().Any(a => a.Name == "TEntityType"));

    foreach (var assembly in AppDomain.CurrentDomain
      .GetAssemblies()
      .Where(a => a.GetName().Name != "EntityFramework"))
    {
      var configTypes = assembly
        .GetTypes()
        .Where(t => t.BaseType != null
          && t.BaseType.IsGenericType
          && t.BaseType.GetGenericTypeDefinition() ==     typeof(EntityTypeConfiguration<>));

      foreach (var type in configTypes)
      {
        var entityType = type.BaseType.GetGenericArguments().Single();

        var entityConfig = assembly.CreateInstance(type.FullName);
        addMethod.MakeGenericMethod(entityType)
          .Invoke(modelBuilder.Configurations, new object[] { entityConfig     });
      }
    }
  }
}

Что если модель изменится?Code First Migrations для спасения ... Возможно, вы не сможете использовать Migrations из консоли диспетчера пакетов, потому что логика для обнаружения вашей модели может потребовать запуска полного приложения.К счастью, эти команды - просто тонкие обертки над API.Вот некоторый код для автоматического изменения базы данных при добавлении новых классов или свойств в модель.В моем недавнем сообщении в блоге содержится более подробная информация о вызове миграций из кода.

var config = new DbMigrationsConfiguration<MyContext> {     AutomaticMigrationsEnabled = true };
var migrator = new DbMigrator(config);
migrator.Update();
1 голос
/ 03 января 2012

Добавление и удаление полей во время выполнения не является хорошей идеей для начала.
Структура базы данных должна быть статической, поскольку она должна отражать структуру вашего класса, а структура вашего класса является статической, хотите вы этого или нет.

Если у вас есть динамическая таблица, вам лучше ее реализовать, например, иметь таблицу с полями "rowID, field, value" и заполнять значения таким образом.

Если вам действительно нужно добавлять / удалять поля в таблице во время выполнения, вы можете создать хранимую процедуру, которая добавляет / удаляет поле, а затем сопоставить SP с Entity Framework.
Это, однако, может вызвать много проблем, потому что Entity Framework не сможет отобразить / снять отображение новых / удаленных полей, и, следовательно, произойдет сбой, когда вы попытаетесь получить доступ к указанной таблице.

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