none
Entity Framework 4.1コードファーストで、接続先を複数指定するには? RRS feed

  • 質問

  • Entity Framework 4.1コードファーストで開発をしています。

    外出先で持ち運べるノートPCで使うアプリで、アプリ本体と一緒にSQL server Compact4.0をデータの置き場として作っています。外から戻ったら、追加や更新などを、事務所のサーバ機のSQL server 2008R2 などへ反映する、というような仕組みにしたいと思っています。

    そのためには当然、ノートPCのCompact4.0の方と、事務所のサーバ機のSQLserverの方とに、同時または連続でConnectionを作る必要があります。そのやり方がわからず困っています。

    Entitiy Frameworkを使わず、ただのADO.NETでアクセスするなら、サーバ機へは(Windows認証の場合)

     

    SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
    builder.DataSource = "(local)\\SQLEXPRESS";
    builder.InitialCatalog = "HogeHogeDB";
    builder.IntegratedSecurity = true;
    using (SqlConnection con = new SqlConnection(builder.ConnectionString))
     {
        con.Open();
        ...(以下、SQL文発行処理など)
    

     

    同様にノートPCのCompactの方へは

     

    SqlCeConnectionStringBuilder builder = new SqlCeConnectionStringBuilder();
    builder.DataSource = "|DataDirectory|HogeHoge.sdf";
    builder.FileMode = "Read Write";
    using (SqlCeConnection con = new SqlCeConnection(builder.ConnectionString))
     {
        con.Open();
        ...(以下、SQL文発行処理など)
    

     

    などとすれば、それぞれ接続できますので、ノートのCompactの方から、追加や更新されたレコードだけDataSetに引っ張ってきて、それを事務所のサーバ機に書き込んでやれば一応できるわけですが、せっかくEntity Frameworkを使っているので、この処理だけ例外的に従来のADO.NETを使うのではなく、Entity Frameworkで統一したいのです。

     

    Entity Framework 4.1のコードファーストで、接続先のDBを変更する方法は、「接続先が1つだけ」の場合は、いくつか方法があることはネットで調べていてわかりました。

    コンソールアプリ(や、WindowsFormsも?)の場合は、App.configに

    <?xml version="1.0" encoding="utf-8"?>
     <configuration>
       <connectionStrings>
       <add name="ItemCatalog"
            connectionString="Data Source=|DataDirectory|HogeHoge.sdf"
            providerName="System.Data.SqlServerCe.4.0"/>
       </connectionStrings>
     </configuration>
     
    

    などと書いてやるだけでいいようですが、WPFの場合はこれはうまく行かないようなので、コードビハインドで

     Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0", "", "Data Source=|DataDirectory|HogeHoge.sdf");
    
    

    と書くことで、外出先で読み書きするローカルのSQL server Compact4.0を指定しています。

    接続先がノートPC内ローカルのSQLserverCompact4.0の1つだけなら、これで良いのですが、そこから読み込んだデータを事務所のサーバへ反映させるためには、そちらへもConnectionを張らないといけません。

    ネットで色々調べていたところ、コードファースト以前のEntity Frameworkの場合ならば、EntityConnectionStringBuilderというのを使って、接続文字列を作れたようですが、どうやらそれを使うには、CSDL,SSDL,MSL などが必要なようで、なまじコードファーストで作っているため、それらのファイルは存在せず(バックグラウンドで見えないところでどこかには作られているのでしょうけど)、この方法も使えないようでした。

    Entity Framework 4.1コードファーストで、接続先を複数指定する方法はあるのでしょうか?




    • 編集済み minami259 2012年1月26日 4:37
    2012年1月26日 4:35

回答

すべての返信

  • http://msdn.microsoft.com/en-us/library/gg696637(v=vs.103).aspx

    DbContextのコンストラクタに接続文字列渡すタイプのものがあります。
    これ使えませんかね。

    #動作の確認とかはしてません。


    あおい情報システム株式会社 小野修司(どっとねっとふぁん)
    • 回答としてマーク 山本春海 2012年2月6日 7:32
    2012年1月26日 5:24
  • 返信ありがとうございます。

    試しに、SqlCeConnectionStringBuilderを使って接続文字列を作って、

    ①その文字列をそのままDbContextのコンストラクタに渡してみる

    ②その文字列を.SqlCeConnectionのコンストラクタに渡してConnectionを作り(質問の中で書いているのと同様)、そのConnectionを、DbContextのコンストラクタに渡してみる

    という2つを試してみたところ、①はエラーになってしまい実行できませんでしたが、②では、同時に2つのDBを開いて、片方からもう片方にコピーするのもできました。

    ②でConnectionのコンストラクタに渡している接続文字列と、①でDbContextに渡している接続文字列は、同一のSqlCeConnectionStringBuilderから作られた、全く同じ文字列なので、②がうまく動くのに①がエラーというのはなぜか理由がわかりませんが…。

    しかし、とりあえず②の方法で、なんとかできるようです。ありがとうございました。


    • 編集済み minami259 2012年1月26日 7:33
    2012年1月26日 7:32
  • 試しに、SqlCeConnectionStringBuilderを使って接続文字列を作って、

    ①その文字列をそのままDbContextのコンストラクタに渡してみる

    ②その文字列を.SqlCeConnectionのコンストラクタに渡してConnectionを作り(質問の中で書いているのと同様)、そのConnectionを、DbContextのコンストラクタに渡してみる

    という2つを試してみたところ、①はエラーになってしまい実行できませんでしたが、②では、同時に2つのDBを開いて、片方からもう片方にコピーするのもできました。

    ②でConnectionのコンストラクタに渡している接続文字列と、①でDbContextに渡している接続文字列は、同一のSqlCeConnectionStringBuilderから作られた、全く同じ文字列なので、②がうまく動くのに①がエラーというのはなぜか理由がわかりませんが…。


    接続文字列をそのまま渡すと、System.Data.SqlClient がデフォルトのプロバイダーとして使用されるらしいので、その影響ではないでしょうか?

    Using DbContext in EF 4.1 Part 2: Connections and Models - ADO.NET team blog - Site Home - MSDN Blogs
    http://blogs.msdn.com/b/adonet/archive/2011/01/27/using-dbcontext-in-ef-feature-ctp5-part-2-connections-and-models.aspx
    2012年1月26日 8:04
  • 返信ありがとうございます。

    You can pass a full connection string to DbContext instead of just the database or connection string name. By default this connection string is used with the System.Data.SqlClient provider;

    ってところですね。『データベース名や接続文字列の名前の代わりにフルで接続文字列そのものを渡せる、規定ではその接続文字列はSqlClientに使われる』と。

    その続きを見ると

     this can be changed by setting a different implementation of IConnectionFactory onto context.Database.DefaultConnectionFactory.

    …『DbContextを継承したクラスのDatabase.DefaultConnectionFactoryプロパティに、IConnectionFactoryインターフェイスの異なった実装をすることでこの挙動を変えることができる』…って感じでしょうかね?

    それ以上の説明やコード例などもないので、いまいちよくわかりませんが。質問文の中で、単一のConnectionだけでよい場合には、コードビハインドで

    Database.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0", "", "Data Source=|DataDirectory|HogeHoge.sdf");
    
    

    としていました。

    が、この場合のDefaultConnectionFactoryは、Databaseクラスのstaticなプロパティでしたから、全てのContextに影響してしまいます。要はこれを、複数のContextにそれぞれ別々に設定できて、それさえできれば後は接続文字列を渡すだけで良さそうですけどね…。

    2012年1月26日 11:26
  • コード ビハインドに接続文字列を直接書いてしまうよりは、App.config に接続文字列を入れておいて ConfigurationManager.ConnectionStrings で取ってくる方がすっきりするんでしょうけど。
    WPF だと DbContext は App.config の接続文字列を、名前から拾ってきてくれないんでしたっけ?(確かめないで言ってます。)
    2012年1月26日 12:43
  • とりあえずは、Connectionを作ってしまってそれをContextに渡してしまうことで一応やりたいことはできますし、これでよしとしておきます。いろいろありがとうございました。
    2012年1月28日 4:50