13

web.config で接続文字列を使用する代わりに、カスタム接続文字列を EF コンテキストに挿入したいと考えています。アイデアは、データベース関連のすべてのロジックを MVC プロジェクトから別のレイヤーに移動することです。また、Web アプリケーションではなく、このレイヤーが適切な接続文字列を担当するようにしたいと考えています。

現在コンテキストを使用しているサービスは、デフォルトのコンストラクターを呼び出しています。

using (var context = new MyDbContext()) {
    //...
}

デフォルトのコンストラクターは、次DbContextの接続文字列の名前で内部的に呼び出していますweb.config

public partial class MyDbContext : DbContext
{
    public MyDbContext()
        : base("name=MyDbContext")
    {
    }

    //...
}

カスタム接続文字列を挿入するには、接続文字列を引数として受け取るオーバーロードされたコンストラクターが必要です。残念ながら、そのようなコンストラクタは提供されていません。

このクラスは自動生成され、すぐに上書きされるため、コンストラクターのオーバーロードをMyDbContextクラス内に手動で追加することは非常に悪い考えであることは明らかです。これ以上これについて話すのはやめましょう、それは禁じられています。限目。

は部分クラスなのでMyDbContext、別のクラス ファイルに追加のコンストラクタを追加することもできますpartial class MyDbContextが、これも臭いようです。理由はわかりませんが、私の脳は悪い考えを言っています。

Model.Context.tt調査の結果、C# といくつかのテンプレート マークアップを組み合わせた T4 テンプレートを編集することで、EF にこの追加のコンストラクターを含めるように指示できることがわかりました。元のコンストラクタは次のとおりです。

public <#=Code.Escape(container)#>()
    : base("name=<#=container.Name#>")
{
<#
    WriteLazyLoadingEnabled(container);
#>
}

同様のロジックを追加して、接続文字列を含むオーバーロードされたコンストラクターを生成するのは明らかに簡単です。

public <#=Code.Escape(container)#>(string nameOrConnectionString)
    : base(nameOrConnectionString)
{
<#
    WriteLazyLoadingEnabled(container);
#>
}

これを試してみたところ、モデル クラスの再生成と DB からのモデルの更新の両方が T4 テンプレートに影響しないため、追加のコンストラクターが常に存在することに気付きました。良い!一見、これは適切なソリューションのように見えますが...

そして、ここに私の質問があります:それは本当に良い解決策ですか?

3 つのオプションをもう一度比較してみましょう。

  1. 自動生成されたクラスを編集します (わかりました、これについては忘れることに同意しました)
  2. コンストラクターを部分クラス ファイルに追加する
  3. T4 テンプレートを編集して、追加のコンストラクターを生成するように EF に指示します。

これら 3 つのオプションのうち、3 番目のオプションが最も便利でクリーンなソリューションのように思えます。あなたの意見は何ですか?誰かが正当な理由を持っていますか、なぜこれが悪い考えになるのでしょうか? おそらくカスタムを使用して、接続文字列を挿入するためのオプションは他にありますconnectionFactoryか? もしそうなら、どうすればいいですか?

4

2 に答える 2

3

@shaft が提案したように、T4 テンプレート アプローチを部分クラスの使用に置き換えました。結局のところ、これは私が現在知っている他のどのソリューションよりもはるかにシンプルで直感的です。

自動生成されたクラスは次のようになります。

public partial class MyDbContext : DbContext
{
    public MyDbContext() : base("name=MyDbContext")
    {
    }

    //...
}

同じ名前の別の部分クラスを追加しました。問題が解決しました。

public partial class MyDbContext 
{
    public MyDbContext(string nameOrConnectionString)
             : base(nameOrConnectionString) 
    {
    }
}
于 2013-06-14T07:45:17.380 に答える
2

提供された 3 つのオプションから、オプション 2 を選択したいと思います。自動生成されたファイルの問題を解決するために、partial キーワードが導入されていませんか? 私の意見では、T4 テンプレートを使用すると複雑さが増します。維持する開発者は、もう 1 つ理解する必要があります (誰もが T4 に精通しているわけではありません) が、部分クラスを拡張することは、より標準的な C# 開発です。

ただし、「本当に良い解決策はありますか」という答えはわかりません。ファクトリを導入すると、維持、テスト、および理解するための新しいコードが再びもたらされます。ファクトリ自体がインスタンス化する必要があるため、この抽象化がここで役立つかどうかはわかりません。 dbcontext を適切なコンストラクター (とにかく提供する必要があります) と共に使用します。

編集:

もう一度考えてみてください: ファクトリは別の場所から接続文字列を解決するのに役立つかもしれません (web.config に接続文字列が必要ないと言いました) が、それでもコンストラクターの問題は解決しません。

于 2013-10-08T14:26:03.003 に答える