none
DBの種類に依存しないDbContextの書き方 RRS feed

  • 質問

  • Visual Studio 2019
    .NET Core 2.2

    ASP .NET Core 2.2 APIアプリケーションの作成を試みていますが、DBの種類に依存しない書き方が分かりません。

    通常、Startupクラス内で下記のようにDbContextを設定していくと思います。

            public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    
                services.AddDbContext<LogContext>(opt =>
                        opt.UseSqlServer(Configuration.GetConnectionString("DefaultContext"))
                );
            }

    しかし、UseSqlServer()を利用している以上、SQLServerに依存したコードになっています。
    例えばOracleを利用する場合はUseOracle()に変更しなければならないかと思います。

    これだとアプリケーションで利用するDBの種類が一択に絞られてしまい、融通が利かせづらくなってしまいます。
    .NET Frameworkでいうと以下のようにDbProviderFactoriesを利用した接続ができると思いますが、同じような手法でDBの種類を外出しにし、共通的なコードでDbContextの設定の仕方はできないのでしょうか?

    var pf = DbProviderFactories.GetFactory("プロバイダ名");
    var conn = pf.CreateConnection();
    conn.Open();

    2019年10月18日 6:13

すべての返信

  • takiruさん、こんにちは。フォーラムオペレーターのHarukaです。
    MSDNフォーラムにご投稿くださいましてありがとうございます。

    これは、接続文字列を動的に変更する方法に似ています。
    パラメータをコンテキストに渡し、データベースの「OnConfiguring」関数でデータベースを設定できます。
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if( )
           {
                    var connString = BuildConnectionString(); // Your connection string logic here
                    optionsBuilder.UseSqlServer(connString);
            }
            Else()
            {
    
            }                                                  
            
        }

    以下のコードサンプルをご参照いただければと思います。

    https://stackoverflow.com/a/43078074/5751404

    https://stackoverflow.com/a/40837070/5751404

    https://stackoverflow.com/a/55907102/5751404


    どうぞよろしくお願いいたします。

    MSDN/ TechNet Community Support Haruka
    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、 ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年10月24日 2:04
    モデレータ
  • Haruka 様

    ご回答ありがとうございます。

    内容を確認させていただきましたが、UseSqlServer()としている以上、
    接続文字どころか利用するDBがOracleになった時に対応できないように
    見受けられました。

    仮に接続文字列をOracle用に設定し、UseSqlServer()を実行すると、
    『そんなSQL Serverのインスタンスはない』旨の例外が発生します。

    接続文字列はどうでもいいのですが、DBの種類に依存しないコードの書き方をして、コードは一切変更せず実現したいのですが・・・。
    もしかしてif()としているところで、想定するDBの接続をすべて列挙しなければならないということでしょうか?

    2019年10月24日 4:34
  • takiruさん、こんにちは。フォーラムオペレーターのHarukaです。
    ご返信いただきありがとうございます。

    クエリ文字列をリクエストに渡し(またはパラメータ名をdbcontextに渡す)、使用するデータベースを特定し、 `OnConfiguring`で使用しているデータベースの現在のインスタンスを特定します。

        private HttpContext _httpContext;
    
        public MyDbContext(DbContextOptions options, IHttpContextAccessor httpContextAccessor) 
              : base(options)
        {
           
            _httpContext = httpContextAccessor.HttpContext;
        }
    
    
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
             var databaseQuerystringParameter = _httpContext.Query["database"].ToString();
             if (!databaseQuerystringParameter.IsNullOrEmpty())
                {
                    //set your connectstring and use sql server  as provider
                  var dbConnectionString = ...
                  optionsBuilder.UseSqlServer(dbConnectionString);
                }
                else
                {
                   //set your connectstring and use oracle as provider 
                }
    }
    


    また、DIにdbコンテキストを登録するときに、データベースプロバイダーを削除できます。

    services.AddDbContext<LogContext>();


    別の解決策は、スタートアップでプロバイダーを直接設定することです:

    public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IHttpContextAccessor, HttpContextAccessor>();
    
            services.AddDbContext<Db2Context>(((serviceProvider, options) =>
            {
                var httpContext = serviceProvider.GetService<IHttpContextAccessor>().HttpContext;
                var httpRequest = httpContext.Request;
    
                // Get the 'database' querystring parameter from the request (if supplied - default is empty).
               // TODO: Swap this out for an enum.
                var databaseQuerystringParameter = httpRequest.Query["database"].ToString();
    
           
    
                if (!databaseQuerystringParameter.IsNullOrEmpty())
                {
                    //set your connectstring and use sql server  as provider 
                    var dbConnectionString = ...
                    optionsBuilder.UseSqlServer(dbConnectionString);
    
                }
                else
                {
                    //set your connectstring and use oracle as provider 
                }
    
              
            }
        )

    また、asp.netコアのOracleプロバイダーを追加します。
    https://www.oracle.com/webfolder/technetwork/tutorials/obe/db/dotnet/ODPNET_Core_get_started/index.html

    どうぞよろしくお願いいたします。


    MSDN/ TechNet Community Support Haruka
    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、 ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年10月25日 7:03
    モデレータ
  • Haruka 様

    ご回答ありがとうございます。

    やはりシステムとしてサポートするDBごとに全部記述しなければならないのですね。

    2019年10月29日 0:12
  • takiruさん、こんにちは。フォーラムオペレーターのHarukaです。
    ご返信いただきありがとうございます。

    >やはりシステムとしてサポートするDBごとに全部記述しなければならないのですね。
    →それについて詳しく説明していただけませんか。各dbプロバイダーに正しく設定する必要があります。

    どうぞよろしくお願いいたします。

    MSDN/ TechNet Community Support Haruka
    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、 ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年10月29日 7:45
    モデレータ
  • Haruka 様

    私が求めていたものは、システムとしてサポートするDBの種類を設け、実際にシステムを構築する場面では
    ユーザーにDB選定を委ねることができ、SQL ServerでもOracleでもMySQLでもPostgreSQLでも利用でき、
    プログラムを直さずとも、DBの種類について少しの設定ファイルの変更を行うだけでいいようにしたいということです。

    それを実現するにあたって、プログラムで、想定するDBの記述を全部記述することなく利用を実現するコード方法はないのかな?というところです。

    一度システムを構築したのに、後から動的にDBを切り替えたいとか、あるデータの通信のみ別なDBとやりとりをしたい、といったことではありません。

    2019年11月5日 9:16
  • takiruさん、こんにちは。フォーラムオペレーターのHarukaです。
    ご返信いただきありがとうございます。

    いいえ、今のところでは、システムで最初に各dbプロバイダーを登録する必要がまだありますが、使用するdb/dbcontextを動的に選択できます。

    ユーザーが使用するdbを選択するためのUIを提供できます。ロジックは要件によってカスタマイズできます。

    どうぞよろしくお願いいたします。

    MSDN/ TechNet Community Support Haruka
    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、 ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年11月6日 7:36
    モデレータ
  • Haruka様

    大変お手数ですが、コードのご提示をしていただくことは叶いませんでしょうか?
    可能ということは、UseSqlServer()やUseOracle()といった拡張メソッドを一切利用しない方法があるという認識です。

    • 編集済み takiru 2019年11月7日 2:01
    2019年11月6日 14:52
  • takiruさん、こんにちは。フォーラムオペレーターのHarukaです。
    ご返信いただきありがとうございます。

    >可能ということは、UseSqlServer()やUseOracle()といった拡張メソッドを一切利用しない方法があるという認識です。
    →dbコンテキストの現在のインスタンスが任意のデータベースを使用するようにロジックを記述することができます。
    拡張メソッドはただ、コードを明確かつ単純にするのに役立ちます。

    どうぞよろしくお願いいたします。

    MSDN/ TechNet Community Support Haruka
    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、 ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年11月7日 7:44
    モデレータ