射撃しつつ前進する方への援護射撃です。
群馬に行った時、データセットの件で「う~ん」と思い、なんとなく落とし穴に陥りそうな匂いはしていたのですが、時間が取れずにそのままに。
という訳で遅ればせながら、.NET(C#)でMySQLを扱うときのコツなんかを、詳しめに書いておきます。
■接続方法はADO.NET Driver for MySQL (Connector/NET)を使う
まず、.NETから扱えるように下記をダウンロードしてインストールします。
MySQL :: Download Connector/Net
http://www-jp.mysql.com/downloads/connector/net/
■名前空間は MySql.Data.MySqlClient
SQL Server の場合は System.Data.SqlClient を使いますが、MySQL の場合は MySql.Data.MySqlClient をインポートします。
C# だったら先頭の行に
using MySql.Data.MySqlClient;
でOK
■主なクラス
ADO.NET経由でSQL Serverを扱う場合は、
コネクション SqlConnect
アダプタ SqlDataAdapter
となっています。
これが MySQL の場合は
コネクション MySqlConnect
アダプタ MySqlDataAdapter
となればOK。
巷のADO.NETのサンプルもこれを書き換えれば大抵動きます。
肝心のDataSet、DataTable クラスに関しては、SQL Serverでも MySQL でも同じものを使います。最初のコネクションとアダプタの名前が違うだけです。使い方は統一されているので、クラス名だけ変えれば普通は通ります。
■サンプル
いわゆる、こんな画面を作ってデータ接続をテストすると場合
サンプルコードはこちら
// クリアボタン private void button1_Click(object sender, EventArgs e) { // 挿入時のクリア dataGridView1.Columns.Clear(); // バインド時 dataGridView1.DataSource = null; } // DataSetボタン private void button2_Click(object sender, EventArgs e) { // コネクション作成 MySqlConnection cn = new MySqlConnection( “Data Source=localhost;Database=konicadb;User ID=konica;password=konica”); MySqlDataAdapter da = new MySqlDataAdapter( “SELECT * FROM sample”, cn); DataTable dt = new DataTable(); // 検索 da.Fill(dt); // 表示 dataGridView1.DataSource = dt; // データ保持 m_dt = dt; } /// /// データ保持用 /// DataTable m_dt; // DataSet自前ボタン private void button3_Click(object sender, EventArgs e) { // コネクション作成 MySqlConnection cn = new MySqlConnection( “Data Source=localhost;Database=konicadb;User ID=konica;password=konica”); MySqlDataAdapter da = new MySqlDataAdapter( “SELECT * FROM sample”, cn); DataTable dt = new DataTable(); // 検索 da.Fill(dt); // 自前で表示 dataGridView1.Columns.Add(“ID”, “ID”); dataGridView1.Columns.Add(“name”, “名前”); foreach (DataRow item in dt.Rows) { int n = dataGridView1.Rows.Add(); dataGridView1.Rows[n].Cells[0].Value = item["id"]; dataGridView1.Rows[n].Cells[1].Value = item["name"]; } } // 保存済みのDataSetボタン private void button4_Click(object sender, EventArgs e) { // 表示 dataGridView1.DataSource = m_dt; } // LINQは動かせない private void button5_Click(object sender, EventArgs e) { // これはSQL Serverしかできない string cnstr = “Data Source=localhost;Database=konicadb;User ID=konica;password=konica”; DataContext dc = new DataContext(cnstr); var tb = dc.GetTable(); dataGridView1.DataSource = tb; } [TableAttribute(Name = "sample")] public class TSample { public int ID { get; set; } public string Name { get; set; } public DateTime UpdateDate { get; set; } }
データグリッドで表示するだけならば、DataSourceプロパティを使ったほうが簡単です。列名なんかが固定であれば、デザイン時に表示する文字列を入れて、バインドする列名を入れておけばOK。
DataSet(ここではDataTable)の使いどころは、保存済みのDataSetボタンのところのように、一度キープしたものをデータベースに接続せずに使えることですね。いわゆるキャッシュの役割です。
当然、DataSetに一時的に更新状態をキープして、一気にデータベースにコミット、という流れもできるんですが、型付きDataSetを作らないと効率的でないので、最初は避けたほうがよいかなと思っています。MySqlCommand を使って、ちまちま INSERT文やUPDATE文を書いたほうが、後々の見通しが良くなります(経験上ですが)。
■DataSetとは何ぞや?
という訳で、DataSetとは何ぞやを、もうちょっと。
最初にデータベース接続に関しては歴史的に、
– ODBC接続
– RDO,DAO,ADO
– ADO.NET, DataSet
– ADO.NET, 型付きDataSet
– LINQ to SQL
– ADO.NET Data Entity
な流れがあります。
ODBC接続は、SQL文を流してちまちまと受け取る方法ですね。Oracleで埋め込み型のPL/SQLを使っているとカーソルを使ったり、フェッチを使ったりとややこしいことこの上ないのですが、C言語からモロ扱えるしろものです。今でも結構やります。
これじゃあ、大変という訳でRDO,DAO,ADOなんてのが出来ました。
主にVBやExcel VBAから使っていたもので、接続する方法をCOM/ActiveXなんかで扱えるようになっています。VB6ぐらいにはお世話になったものです。VB6自体は本格的なオブジェクト指向言語ではない(一部、クラスが使えますが)ので、C++で作成したActiveXを使うという形で、「オブジェクト」を扱うん出うのです。
これを VC++で使っていたりしました。
この最終形のADO(ActiveX Data Objects)の.NET版が、ADO.NETです。
最初は、ADOの移植版という形。
その中でDataSetというのが、データキャッシュの役割を持ちます。
おそらく当時、ASP.NETを作った関係で、WEBサイトのキャッシュをする必要があってのDataSetかなぁ、と。
最初、DataSetは型がない(列名を持たない)ので、アクセスするときのパフォーマンスが落ちました。また、C#のような厳密にメンバを指定したい場合なんかは、文字列で列名を書くのはちょっと…な感じでした(Row[“name”]みたいなの)。
これを、Tsample.name のようにプロパティ名にしたいなぁ、と思ったのが型付きDataSetの始まりです。
この型付の話は、当時、データベースとオブジェクト指向を繋げるという意味で、「O/Rマッピング」と言われています。今では、この手の自動生成ツール(Ruby on Railsとか)が主流になりましたが、その最初の頃ってな感じです。
O/Rマッピングが流行って、データベースからクラスのコードを自動生成してくるのに慣れてくると、一方で SQL 文をプログラマが書かなくなったんですね。自前のデータアクセス方法を提案し始めたというところです。
それが、LINQであったり、という訳で、LINQ to SQL なんかがあります。
LINQ自体は、データベースに限らないのですが、まあ、関数言語の良いとこ取りな感じで。
一方で、ADO.NET Data Entity というのがあって、これがDataSetの正式な子供ですね。Visual Studio でデータベースに接続して、データクラスを自動生成してってやり方です。
このような流れの中で、MySQL は
– ADO.NET, 型付きDataSet
– LINQ to SQL
– ADO.NET Data Entity
のところが使えません。厳密には型付きDataSetは使えるのですが、ちまちまと自前で作らないといけないので、メンテ上非常に大変(それを上回る保守コストならば別ですが)。
なので、MySQL+.NETという組み合わせでは、MySQLのConnectorを使って DataSet/DataTable を使うのが定番かと思います。
■DataSetの使いどころ
MSさんの宣伝記事ならば、
DataSetで、複数のデータ更新ができるのでデータベースに直結せずに、全てのCRUD処理をDataSetを媒介したほうが効率が良い。
と言いたいところなのですが、現場レベルとしては、ちょっと困るところが出てきます。
1)複数のテーブルが連携しているときの処理が分かりずらい。
2)大量のデータを更新中に、DataSet内で止まってしまう。
のようなお困りが発生します。
1)のほうは、マスターテーブルのような単純なテーブルに関しては DataSet/DataTable を使うと非常に早く更新ができるので楽です。
ですが、他のテーブルのリレーションがあった場合、同時更新などで別のキーを参照する場合の時は、コミットする前の場合、DataSet内のテーブルを探らないと駄目なので、この処理が非常に面倒です。なので、この場合は、トランザクションを付けて、直接データベースにアクセスしたほうが楽にコーディングができます。
2)のほうは、致命的なところがあって、データ量が非常に多くなる(1万件など)場合は、DataSet自体のメモリが大きくなると同時に、更新時にいちいちデータのチェックが走るので、結構重たい処理になってしまいます。この更新処理をDataSet内部のコードを弄って、分割したりするよりは、素直に更新時は直接データベースにアクセスにしに行ったほうがすっきりしたコードが書けます。
という訳で、実際はこんな風に使います。
ええ、なんか見たことがある矢印の向きですよね。
こんな風に、MVCスタイルにするとコードが見やすくなります。
つまり、コントローラ部分を分離させた方が、コードの見通しが良くなる、という予想が立ちます(実際、そうなります)。
おお、感謝(´・ω・)ス
早速内容視姦して再度理解してみるです。
本当にデータベース絡み・・・しっかり覚えないですね。
>なので、MySQL+.NETという組み合わせでは、MySQLのConnectorを使って >DataSet/DataTable を使うのが定番かと思います。
MySQLのConnectorはライセンスがGPLですか。
Connectorを使用する側のアプリもGPLにしないとライセンス上、まずい感じになってしまいますよね。
作るMySQL+.NETアプリのライセンスもGPLにするのが定番なんでしょうか?
Connector/NET って、LGPL かと思ってたら GPL なんですね。なるほど。
MySQL :: MySQL のライセンスポリシー
http://www-jp.mysql.com/about/legal/licensing/index.html
MySQL – ライセンス早分かり – MySQL, Qooker, VG-Sync, BitDefender, IP-PBX
http://www.softagency.co.jp/products/mysql/license/
となると、
・個人的に使う場合は、ソース公開は必要なし(配布しないので)
・一般に配布する場合は、GPL でソース公開(OSSとか)
・販売する場合は、ライセンスを買う。
ってのが定番みたいです。
Connector/NET 部分を別プロセス(あるいは別ツール)にして、Connector 周りは LGPL でソース公開して、実アプリの場合は非GPL(通常の商用アプリ)にする、っていう切り離し方法…というか抜け道があります。このあたりがややこしいので、ライブラリとして使うものは LGPL だったりするのですが、あえて LGPL じゃなくて GPL にしてあるあたりが「法的に絡めて取る」気満々みたいなので、なんかあるとやばそうだなぁという気もしてきますね。
追記、やっぱり Connector は LGPL から GPL に変更されていたのか。
最初の至高の技を書いたときに LGPL だから、そのままの記憶が orz
なるほど、昔はLGPLだったんですね。
初めてMySQLと繋げようとしているので、どうやって実現するか悩み中ですが、Connectorは避けた方が無難ですね。
ちなみに「抜け道」のやり方はまずいと思います。
GPLのFAQによると、GPLライブラリを使用して、LGPLでリリースする場合は、GPLにしないといけないようです。
http://www.gnu.org/licenses/gpl-faq.en.html#AllCompatibility
ちと、亀レスになってしまいましたが。。
ああ、確かに GPL->LGPLのラップはダメですね。GPLに「汚染される」という形で。
となると、MySQL+生のADO.NETを使うってのが良さそうに思えたのですが、
MySQL を含んだアプリを使うときには、結局ライセンス購入が発生するので、
MySQL+Connector/NETのライセンスをワンセットで購入、というのがベターかもしれませんね。