Это вербатин, взятый из блога Роуэн Миллер.
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();