2012-09-29 5 views
11

私は、モジュール式Non-Monolithicアプリケーションの設計でORM(この場合はEF5)を使用するアプローチについての提案を探しています。コアが第三者のモジュールを直接参照していないコアパートとサードパーティのモジュール、モジュールはコア/コモンテーブルとクラスのみを参照しています。EF:ModularアプリケーションのDatabaseFirst DbContextのデザイン戦略を検索しています

議論のために、十分に近似するのはDNNです。

CodeFirst:

CodeFirstでは、私が使用したアプローチは、DBのモデルを構築することでしたリフレクション経由したコアのDbContextのDbInitialation段階で、私は、任意のDLL内の任意のクラスを見つけるためにリフレクションを使用(例えばコアまたはさまざまなモジュール)をIDbInitializer(Execute()メソッドを含むカスタムコントラクト)で装飾して、DLLの構造だけを定義します。各dllはDbModelにそれ自体について知っていたものを加えました。 その後のシード処理も同じwaで処理されました(特定のIDbSeeder契約を検索して実行)。

プロ: *アプローチは今のところ動作します。 *同じコアDbContextは、各リポジトリがdbContextのプロパティであると予想するのではなく、dbContext.GetSet()を使用する限り、すべてのレポジトリで使用できます。いいえ。 短所: *起動時のみ動作します(つまり、新しいモジュールを追加するにはAppPoolを更新する必要があります)。 * CodeFirstはPOCに最適です。しかし、EF5では、エンタープライズワークのためにはまだ十分ではありません(StoredProcsのEF6やその他の機能が追加されるのを待つことができません)。 *私のDBAは、少なくともコアのために、CodeFirstを嫌い、できるだけストアドプロックスでその部分を最適化したい...私たちはチームなので、方法を見つけることができます...

データベース-最初:

DbModel相(組み込み* .edmxリソースファイルからの読み込み)前DbContextのコンストラクタに起こっているように見えます。 DbInitializationは決して呼び出されません(モデルが完全であるとみなされるため)、Coreが知っている以上のテーブルを追加することはできません。

CodeFirstでできるように、モデルに要素を動的に追加できない場合は、* Core DbContextのモデルがDb-Coreおよびすべてのサードパーティのすべてのテーブルの知識を持っている必要がありますモジュール。アプリケーションをモノリシックにし、高度に結合して、私が達成しようとしていることを打ち負かしてください。 *または各第三者はコアテーブルをインポートして *バージョン管理の問題(コアの* .edmxが更新されたときにモジュールが* .edmxを更新しない) *異なるメモリ内のすべての複製コンテキスト=同時実行性の問題を追跡するのは難しい。

この時点で、CodeFirstアプローチは、ModularソフトウェアをEFで実現できる唯一の方法です。しかし、うまくいけば、他の誰かがDatabaseFirstを輝かせる方法を知っているでしょう - 埋め込まれた* .edmxファイルから作成されたモデルにDbSetを「追加する」方法はありますか?

他のアイデアですか?

答えて

1

これはCodeFirstのアプローチであり、最もクリーンな解決策ではありませんが、ここで掲示されている回答のように、起動後も初期化を強制するのはどうでしょうか?Forcing code-first to always initialize a non-existent database?(私はCodeFirstについては何も正確にはわかりませんが、古い投稿はありません。ショットの価値があります)

4

pluginアーキテクチャを使用することを検討します。これは、アプリケーション自体の全体的な設計であるためです。

次の(この例では、StructureMapを使用することに注意してください - ここStructureMap Documentationへのリンクがある)のような何かをすることによって、このの基礎を達成することができます

  1. は、あなたのDbContextオブジェクトができるからインターフェイスを作成します。派生する。 (のStructureMapを使用して)あなたの依存性注入のセットアップで

    public interface IPluginContext { 
        IDictionary<String, DbSet> DataSets { get; } 
    } 
    
  2. - 以下のような何か:あなたのプラグインのそれぞれについて

    Scan(s => { 
        s.AssembliesFromApplicationBaseDirectory(); 
        s.AddAllTypesOf<IPluginContext>(); 
        s.WithDefaultConventions(); 
    }); 
    For<IEnumerable<IPluginContext>>().Use(x => 
        x.GetAllInstances<IPluginContext>() 
    ); 
    
  3. を、どちらか{plugin}.Context.ttファイルを変更 - またはpartial classを追加ファイルでDbContextが生成され、IPluginContextから派生します。

    public partial class FooContext : IPluginContext { } 
    
  4. アルターのようなものを公開するために、各プラグインの{plugin}.Context.ttファイル:

    public IDictionary<String, DbSet> DataSets { 
        get { 
         // Here is where you would have the .tt file output a reference 
         // to each property, keyed on its property name as the Key - 
         // in the form of an IDictionary. 
        } 
    } 
    
  5. あなたは今、次のような何かを行うことができます。

    // This could be inside a service class, your main Data Context, or wherever 
    // else it becomes convenient to call. 
    public DbSet DataSet(String name) { 
        var plugins = ObjectFactory.GetInstance<IEnumerable<IPluginContext>>(); 
        var dataSet = plugins.FirstOrDefault(p => 
         p.DataSets.Any(ds => ds.Key.Equals(name)) 
        ); 
    
        return dataSet; 
    } 
    

があれば、私を許して構文は完璧ではありません - 私はコンパイラ内ではなく、ポスト内でこれをやっています。

最終結果はあなたのような何かする柔軟性提供します:長期的で

// Inside an MVC controller... 
    public JsonResult GetPluginByTypeName(String typeName) { 
     var dataSet = container.DataSet(typeName); 
     if (dataSet != null) { 
      return Json(dataSet.Select()); 
     } else { 
      return Json("Unable to locate that object type."); 
     } 
    } 

明らかにし、 - あなたはコントロールはプラグインが実際には1つであり、反転したいですタイプを予期するサーバーではなく、アーキテクチャーに結びついています。しかし、このような遅延ロードを使用して、メインアプリケーションがすべてのプラグインが結びついているエンドポイントを公開しているのと同じ種類のものを実現することができます。ようなものになるだろう

public interface IPlugin : IDisposable { 
    void EnsureDatabase(); 
    void Initialize(); 
} 

今、あなたのアーキテクチャ(DNNスタイル)のためのプラグインを作成しようとしている任意のアプリケーション開発者に、このインターフェイスを公開することができます - そしてあなたのStructureMapの構成は次のように動作します:

// Global.asax 
public static IEnumerable<IPlugin> plugins = 
    ObjectFactory.GetInstance<IEnumerable<IPlugin>>(); 

public void Application_Start() { 
    foreach(IPlugin plugin in plugins) { 
     plugin.EnsureDatabase(); 
     plugin.Initialize(); 
    } 
} 
:あなたはあなたのアプリケーションを初期化するとき、あなたのような何かを行うことができます今すぐ
Scan(s => { 
    s.AssembliesFromApplicationBaseDirectory(); // Upload all plugin DLLs here 
    // NOTE: Remember that this gives people access to your system!!! 
    //  Given what you are developing, though, I am assuming you 
    //  already get that. 
    s.AddAllTypesOf<IPlugin>(); 
    s.WithDefaultConventions(); 
}); 
For<IEnumerable<IPlugin>>().Use(x => x.GetAllInstances<IPlugin>()); 

各オブジェクトは、独自のデータベース・コンテキストを含むことができ、必要に応じて独自のデータベース・インスタンス/表をインストールし、正常に処理するプロセスを管理できるようになりました。

明らかに、これは完全な解決策ではありませんが、私はそれが役に立つ方向にあなたを始めることを願っています。 :)私がここで何かを明確にすることができれば、私に知らせてください。

関連する問題