ADO.NET Entity Data Modelの接続先を動的に切り替える

LINQを使う時に、ADO.NET Entity Data Modelを作成する、ってのが今後の主流な訳ですが、Data Model を作るときの接続先をアプリケーションを実行するときに、どうやって切り替えられるのか?という問題があって…いや、知らなかっただけなんですけどね。良く見たら MSDN に書いてあったので。

ConnectionString プロパティ
http://msdn.microsoft.com/ja-jp/library/system.data.entityclient.entityconnection.connectionstring.aspx

普通に作成すると、web.config/app.config に書かれるので、さてこれをどうやって実行時に変えたらいいものか?と悩むわけです。某ひと目 Azure でもかなり悩んだ。

ソースコードは MySQL 接続になっていますが、基本的なところは SQL Server でも同じです。

■web.config/app.confg の connectionStrings で切り替える

Data Entity を作ると、config に connectionStrings/add が作成されます。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add name="wordpressEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=MySql.Data.MySqlClient;provider connection string=&quot;server=localhost;User Id=wordpress;password=wordpress;Persist Security Info=True;database=wordpress;Allow Zero Datetime=True;Convert Zero Datetime=True;&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
</configuration>

こんな風に、作成時の接続文字列が作られるので、同じように別の接続文字列も作ってみます。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add name="wordpressEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=MySql.Data.MySqlClient;provider connection string=&quot;server=localhost;User Id=wordpress;password=wordpress;Persist Security Info=True;database=wordpress;Allow Zero Datetime=True;Convert Zero Datetime=True;&quot;" providerName="System.Data.EntityClient" />
    <add name="wp33jEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=MySql.Data.MySqlClient;provider connection string=&quot;server=localhost;User Id=wpuser;password=wppass;Persist Security Info=True;database=wp33jp;Allow Zero Datetime=True;Convert Zero Datetime=True;&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
</configuration>

これを、

// 公開している記事一覧を表示
wordpressEntities ent = new wordpressEntities();

のように接続すると、デフォルトで「wordpressEntities」に接続されるようになっています。ここのコードは、model のファイルを開いて「Model1.Designer.cs」を見ると、次のように name が指定されています。

/// <summary>
/// アプリケーション構成ファイルの 'wordpressEntities' セクションにある接続文字列を使用して新しい wordpressEntities オブジェクトを初期化します。
/// </summary>
public wordpressEntities() : base("name=wordpressEntities", "wordpressEntities")
{
    this.ContextOptions.LazyLoadingEnabled = true;
    OnContextCreated();
}

なので、config ファイルに書いていある別の接続文字列を持ってきたい場合は、次のようにコンストラクタで「name=接続名」を指定します。ここでは、config にあらかじめ設定した「wp33jEntities」を取得して表示します。

private void button3_Click(object sender, EventArgs e)
{
	// web.config から設定値を取得
	wordpressEntities ent = new wordpressEntities("name=wp33jEntities");
	var posts = from t in ent.wp_posts
				where t.post_status == "publish"
				&& t.post_type == "post"
				orderby t.post_date descending
				select new { t.ID, t.post_title, t.post_date };
	// バインド
	dataGridView1.DataSource = posts;
}

■接続文字列を動的に設定する

上記の方法だと、あらかじめ web.config/app.config に接続文字列を書いておかないとだめなので、何らかの独自の設定ファイルからの読み出した情報からはコネクションを構築できませんよね。ユーザー名やらパスワードや、サーバー名などを動的に切り替えたい場合があります。
そんな場合は、接続文字列を独自に作成して渡します。先の「wordpressEntities」クラスは、ObjectContext クラスを継承しているので、直接接続文字列を渡せそうなのですが、普通にデータベースに接続する場合とはちょっと違うので、ConnectionString プロパティ を参考にして、EntityConnection オブジェクトを渡すようにします。

private void button4_Click(object sender, EventArgs e)
{
	// 接続文字列を直接指定
	MySqlConnectionStringBuilder sb = new MySqlConnectionStringBuilder();
	sb.Server = "localhost";
	sb.Database = "wp33jp";
	sb.UserID = "wpuser";
	sb.Password = "wppass";
	sb.AllowZeroDateTime = true;
	sb.ConvertZeroDateTime = true;

	EntityConnectionStringBuilder esb = new EntityConnectionStringBuilder();
	esb.Provider = "MySql.Data.MySqlClient";
	esb.ProviderConnectionString = sb.ToString();
	esb.Metadata = "res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl";
	EntityConnection cn = new EntityConnection(esb.ToString());

	wordpressEntities ent = new wordpressEntities(cn);
	var posts = from t in ent.wp_posts
				where t.post_status == "publish"
				&& t.post_type == "post"
				orderby t.post_date descending
				select new { t.ID, t.post_title, t.post_date };
	// バインド
	dataGridView1.DataSource = posts;
}

なにやらややこしいですが、MySqlConnectionStringBuilder クラスで「接続文字列」を作成しておいて、EntityConnectionStringBuilder クラスでプロバイダ名やメタデータ(テーブル情報)を指定するという具合です。メタデータ自体は Entity Model クラスのファイル名が出てくるので、それぞれ合わせる必要があります。ファイル名が違っているとリソースから読み込めずにエラーになります。ちなみに、SQL Server に接続する場合は、「SqlConnectionStringBuilder」クラスです。
なお、MySqlConnectionStringBuilder クラスを使うには、「using MySql.Data.MySqlClient;」することになります。

このあたりの接続文字列は、Release時とDebug時に切り替えたり、SQL Azure接続とローカルコンピュータへの接続とかに使えますね。

カテゴリー: C#, MySQL パーマリンク