8

ページ、ユーザー、ロール、ナビゲーションなど、複数のプロジェクトで常に再利用されるすべての共通エンティティを含むベースdbcontextを作成しようとしています。

そうすることで、DbContextを継承し、必要なすべてのDbSetを定義するContextBaseクラスができます。次に、プロジェクト固有のDbSetを定義するContextBaseを継承するContextクラスがあります。クラスは次のように定義されています。

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メソッドをオーバーライドするクラスを参照します。

2つのコンテキストクラスは同じ名前空間で定義されていますが、クロスアセンブリ(プロジェクト固有のコードに触れることなく複数の既存のプロジェクトのベースプロジェクトを更新できるようにするため)-これが関連するかどうかはわかりません。

私の問題: このコードを実行すると正常に動作しますが、データベースを調べると、実際には2つの異なるデータベースが作成されます!! 1つはすべての基本エンティティテーブルを含み、もう1つは基本テーブルとカスタムテーブルの両方を含みます。CRUD操作はカスタムバージョン(明らかに私が望むもの)でのみ実行されますが、なぜ他のバージョンのスキーマも作成するのですか?

どんな助けでもありがたいです、ありがとう!

アップデート:

次のコードは私が最終的に得たものです。理想的ではありませんが、機能します。これを改善する方法についてのフィードバックを引き続き受け取りたいと思いますが、それまでの間、これがプロセスの促進に役立つことを願っています。私は本当にこれを行うことをお勧めしません!非常にエラーが発生しやすく、デバッグするのは非常にイライラします。これを実現するためのより良いアイデアや実装があるかどうかを確認するために、これを投稿しているだけです。

まだ存在している(唯一ではない)問題の1つは、MVCビューをプロジェクトに手動で追加する必要があることです。Nugetパッケージに追加しましたが、VSがTFSに接続されている場合、非常に多くのファイルを含むnugetパッケージを適用するのに2〜3時間かかります。さらにいくつかの作業とカスタムビューエンジンを使用すると、ビューをプリコンパイルできます(http://blog.davidebbo.com/2011/06/precompile-your-mvc-views-using.html)。

ソリューションは、ベースフレームワークプロジェクトとカスタムプロジェクトに分割されます(各カテゴリには、独自のモデルとリポジトリパターンが含まれます)。フレームワークプロジェクトはNugetパッケージにパッケージ化されてから、任意のカスタムプロジェクトにインストールされるため、ユーザー、役割と権限の管理、コンテンツ管理などのプロジェクトの共通機能(ボイラープレートと呼ばれることが多い)を簡単に追加できます。新しいプロジェクト。これにより、ボイラープレートの改善を既存のカスタムプロジェクトに移行できます。

カスタムデータベースイニシャライザー:

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

フレームワークのDB移行構成:

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

カスタムプロジェクトのDB移行構成:

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

global.asax AppStartの場合:

        //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>
4

2 に答える 2

5

(コメントから)

ContextBase明らかにジェネリック型引数としてのnew T()ジェネリックメソッドのように、オブジェクトを直接作成しているので、のイニシャライザーも実行されます。オブジェクトの作成を防ぐために(オブジェクトを直接インスタンス化する必要がない場合、派生コンテキストを常に使用する必要がある場合)、クラスをとしてマークすることができます。ContextBaseContextBaseContextBaseabstract

于 2012-10-10T10:58:59.733 に答える
4

ContextBaseイニシャライザもあるようです。これは次の方法で削除できます。

Database.SetInitializer<ContextBase>(null);
于 2012-10-10T10:13:36.003 に答える