2012-10-10 7 views
7

、ユーザー、ロール、ナビゲーションなどEFコード最初:継承されたdbcontextは2つの、私はページのように、常に複数のプロジェクトで再利用されるすべての共通のエンティティを、含まれているベースdbcontextを作成しようとしているデータベース

を作成しますこれを行うには、私はDbContextを継承し、私が望むすべてのDbSetsを定義するContextBaseクラスを持っています。次に、ContextBaseを継承したContextクラスを作成します。ここで、プロジェクト固有の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で:クラスに設定referesがDbMigrationsConfigurationを継承し、シードメソッドをオーバーライド

Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, Configuration>()); 

2つのコンテキストクラスは同じネームスペースに定義されていますが、プロジェクト間での共通コードに触れずに複数の既存プロジェクトのベースプロジェクトを更新できるようにアセンブリを組み合せています。

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

ご協力いただきありがとうございます。

UPDATE:

次のコードは、私がなってしまったものです。理想的ではありませんが、機能します。私はまだこれを改善する方法のフィードバックを得ることが大好きですが、その間に私はこれがプロセスをさらに助けることを願っています。私は本当にこれをお勧めしません!非常にエラーが発生しやすく、デバッグには非常に不満です。私は単にこれを投稿して、これを達成するためのより良いアイデアや実装があるかどうかを確認しています。

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

解決策は、基本フレームワークプロジェクトとカスタムプロジェクト(各カテゴリには独自のモデルとリポジトリパターンが含まれています)に分割されます。フレームワークプロジェクトは、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の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:Global.asaxのAPPSTARTで

//again nothing special 
public class ContextBase: DbContext 
{ 
    //example DbSet's 
    public virtual DbSet<Models.User> Users { get; set; } 
    protected override void OnModelCreating(DbModelBuilder modelBuilder); 
} 

:web.configファイルで

 //first remove the base context initialiser 
     Database.SetInitializer<ContextBase>(null); 
     //set the inherited context initializer 
     Database.SetInitializer(new MyMigrateDatabaseToLatestVersion()); 

<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> 
+0

ベースクラス(または親から渡す)に接続文字列を設定してみてください:public ContextBase():base( "MyConnection") –

+1

また、ContextBaseからベースを呼び出していますか?さらに設定を追加すると、設定ごとにデータベースが作成されますか?設定を追加してから、base.OnModelCreatingを呼び出してみてください。 – MrFox

+1

'ContextBase'コンテキストを直接作成しますか? ( 'new ContextBase()')もしそうしたければ、 'ContextBase'を' abstract'にして、コンパイラフラグがそうしようとしていることを確認することができます。 – hvd

答えて

5

(コメント)

あなたは明らかにジェネリック型引数としてContextBaseと一般的な方法でnew T()として、直接ContextBaseオブジェクトを作成しているので、ContextBaseのための任意の初期化子も実行します。 ContextBaseオブジェクトを作成しないようにするには(派生したコンテキストを常に使用する必要がある場合は直接インスタンス化しないでください)、クラスをabstractとマークできます。

3

あなたContextBaseが同様に初期化子を持っているようです..これを削除することができます

Database.SetInitializer<ContextBase>(null); 
+0

ありがとう、私は上記の@ hvdのコメントによると解決策を見つけましたが、この答えは実際にも私を助けました。 +1 – hofnarwillie

関連する問題