Я пытаюсь создать базовый dbcontext, содержащий все общие сущности, которые всегда будут повторно использоваться в нескольких проектах, таких как страницы, пользователи, роли, навигация и т. Д.
При этом у меня есть класс ContextBase, который наследует DbContext и определяет все DbSets, которые мне нужны. Затем у меня есть класс Context, который наследует ContextBase, где я определяю DbSets для конкретного проекта. Классы определены следующим образом:
public class ContextBase : DbContext
{
public virtual DbSet<User> Users { get; set; }
//more sets
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new UsersConfiguration());
//add more configurations
}
}
public class Context : ContextBase
{
public DbSet<Building> Buildings { get; set; }
//some more project specific sets
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new BuildingsConfiguration());
//add more project specific configs
}
}
В моем global.asax:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, Configuration>());
где Configuration относится к классу, наследующему DbMigrationsConfiguration и переопределяющему метод Seed.
Два класса контекста определены в одном пространстве имен, но перекрестная сборка (для того, чтобы я мог обновлять базовый проект в нескольких существующих проектах, не касаясь кода конкретного проекта) - не уверен, актуально ли это.
МОЯ ПРОБЛЕМА: при запуске этого кода он работает нормально, но при просмотре базы данных он фактически создает две разные базы данных !! Одна содержит все базовые таблицы сущностей, а другая содержит ОБЕИ базовые и настраиваемые таблицы. Операции CRUD выполняются только в пользовательской версии (что, очевидно, то, что я хочу), но почему она также создает схему другой?
Любая помощь приветствуется, спасибо!
ОБНОВЛЕНИЕ:
В итоге я получил следующий код. Это не идеально, но работает. Я все еще хотел бы получить отзывы о способах улучшения этого, но пока я надеюсь, что это поможет дальнейшему процессу. Я ДЕЙСТВИТЕЛЬНО НЕ РЕКОМЕНДУЮ ЭТО ДЕЛАТЬ! Это чрезвычайно подвержено ошибкам и очень сложно отлаживать. Я просто публикую это, чтобы увидеть, есть ли какие-нибудь лучшие идеи или реализации для достижения этой цели.
Одна (но не единственная) проблема, которая все еще существует, заключается в том, что представления MVC необходимо вручную добавлять в проекты. Я добавил его в пакет Nuget, но для применения пакета nuget с таким количеством файлов, когда VS подключен к TFS, требуется от 2 до 3 часов. Приложив дополнительную работу и настроив механизм просмотра, представления можно предварительно скомпилировать (http://blog.davidebbo.com/2011/06/precompile-your-mvc-views-using.html).
Решение разделено на проекты Base Framework и пользовательские проекты (каждая категория включает свои собственные модели и шаблон репозитория). Фреймворк-проекты упаковываются в пакет Nuget, а затем устанавливаются в любые пользовательские проекты, позволяя легко добавлять общие функции любого проекта, такие как управление пользователями, ролями и разрешениями, управление контентом и т. Д. (Часто называемые Boiler Plate). любые новые проекты. Это позволяет переносить любые улучшения шаблона в любые существующие пользовательские проекты.
Настраиваемый инициализатор базы данных:
public class MyMigrateDatabaseToLatestVersion : IDatabaseInitializer<Context>
{
public void InitializeDatabase(Context context)
{
//create the base migrator
var baseConfig = new FrameworkConfiguration();
var migratorBase = new DbMigrator(baseConfig);
//create the custom migrator
var customConfig = new Configuration();
var migratorCustom = new DbMigrator(customConfig);
//now I need to check what migrations have not yet been applied
//and then run them in the correct order
if (migratorBase.GetPendingMigrations().Count() > 0)
{
try
{
migratorBase.Update();
}
catch (System.Data.Entity.Migrations.Infrastructure.AutomaticMigrationsDisabledException)
{
//if an error occured, the seed would not have run, so we run it again.
baseConfig.RunSeed(context);
}
}
if (migratorCustom.GetPendingMigrations().Count() > 0)
{
try
{
migratorCustom.Update();
}
catch (System.Data.Entity.Migrations.Infrastructure.AutomaticMigrationsDisabledException)
{
//if an error occured, the seed would not have run, so we run it again.
customConfig.RunSeed(context);
}
}
}
}
Конфигурация миграции БД Framework:
public class FrameworkConfiguration: DbMigrationsConfiguration<Repository.ContextBase>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
public void RunSeed(Repository.ContextBase context)
{
Seed(context);
}
protected override void Seed(Repository.ContextBase context)
{
// This method will be called at every app start so it should use the AddOrUpdate method rather than just Add.
FrameworkDatabaseSeed.Seed(context);
}
}
Конфигурация миграции БД пользовательского проекта:
public class Configuration : DbMigrationsConfiguration<Repository.Context>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
public void RunSeed(Repository.Context context)
{
Seed(context);
}
protected override void Seed(Repository.Context context)
{
// This method will be called at every app start so it should use the AddOrUpdate method rather than just Add.
CustomDatabaseSeed.Seed(context);
}
}
Пользовательский DbContext
//nothing special here, simply inherit ContextBase, IContext interface is purely for DI
public class Context : ContextBase, IContext
{
//Add the custom DBsets, i.e.
public DbSet<Chart> Charts { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//Assign the model configs, i.e.
modelBuilder.Configurations.Add(new ChartConfiguration());
}
}
Фреймворк DbContext:
//again nothing special
public class ContextBase: DbContext
{
//example DbSet's
public virtual DbSet<Models.User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder);
}
В AppStart global.asax:
//first remove the base context initialiser
Database.SetInitializer<ContextBase>(null);
//set the inherited context initializer
Database.SetInitializer(new MyMigrateDatabaseToLatestVersion());
В web.config:
<connectionStrings>
<!--put the exact same connection string twice here and name it the same as the base and overridden context. That way they point to the same database. -->
<add name="Context" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=CMS2013; Integrated Security=SSPI;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient"/>
<add name="ContextBase" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=CMS2013; Integrated Security=SSPI;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient"/>
</connectionStrings>
ContextBase
контекст напрямую? (new ContextBase()
) Если вы это сделаете, а вы не хотите, вы можете сделатьContextBase
abstract
, чтобы убедиться, что флаги компилятора попытаются это сделать. - person   schedule 10.10.2012