C#でMySQLをDataSetで扱う

射撃しつつ前進する方への援護射撃です。

群馬に行った時、データセットの件で「う~ん」と思い、なんとなく落とし穴に陥りそうな匂いはしていたのですが、時間が取れずにそのままに。

という訳で遅ればせながら、.NET(C#)でMySQLを扱うときのコツなんかを、詳しめに書いておきます。

■接続方法はADO.NET Driver for MySQL (Connector/NET)を使う

まず、.NETから扱えるように下記をダウンロードしてインストールします。

MySQL :: Download Connector/Net

http://www-jp.mysql.com/downloads/connector/net/

20100827_01.jpg

■名前空間は 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 でも同じものを使います。最初のコネクションとアダプタの名前が違うだけです。使い方は統一されているので、クラス名だけ変えれば普通は通ります。

20100827_02.jpg

■サンプル

いわゆる、こんな画面を作ってデータ接続をテストすると場合

20100827_03.jpg

サンプルコードはこちら

// クリアボタン
    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を媒介したほうが効率が良い。

20100827_04.jpg

と言いたいところなのですが、現場レベルとしては、ちょっと困るところが出てきます。

1)複数のテーブルが連携しているときの処理が分かりずらい。

2)大量のデータを更新中に、DataSet内で止まってしまう。

のようなお困りが発生します。

1)のほうは、マスターテーブルのような単純なテーブルに関しては DataSet/DataTable を使うと非常に早く更新ができるので楽です。

ですが、他のテーブルのリレーションがあった場合、同時更新などで別のキーを参照する場合の時は、コミットする前の場合、DataSet内のテーブルを探らないと駄目なので、この処理が非常に面倒です。なので、この場合は、トランザクションを付けて、直接データベースにアクセスしたほうが楽にコーディングができます。

2)のほうは、致命的なところがあって、データ量が非常に多くなる(1万件など)場合は、DataSet自体のメモリが大きくなると同時に、更新時にいちいちデータのチェックが走るので、結構重たい処理になってしまいます。この更新処理をDataSet内部のコードを弄って、分割したりするよりは、素直に更新時は直接データベースにアクセスにしに行ったほうがすっきりしたコードが書けます。

という訳で、実際はこんな風に使います。

20100827_05.jpg

ええ、なんか見たことがある矢印の向きですよね。

20100827_06.jpg

こんな風に、MVCスタイルにするとコードが見やすくなります。

つまり、コントローラ部分を分離させた方が、コードの見通しが良くなる、という予想が立ちます(実際、そうなります)。

カテゴリー: 開発, MySQL パーマリンク

C#でMySQLをDataSetで扱う への6件のフィードバック

  1. konica のコメント:

    おお、感謝(´・ω・)ス
    早速内容視姦して再度理解してみるです。

    本当にデータベース絡み・・・しっかり覚えないですね。

  2. C.John のコメント:

    >なので、MySQL+.NETという組み合わせでは、MySQLのConnectorを使って >DataSet/DataTable を使うのが定番かと思います。
    MySQLのConnectorはライセンスがGPLですか。
    Connectorを使用する側のアプリもGPLにしないとライセンス上、まずい感じになってしまいますよね。
    作るMySQL+.NETアプリのライセンスもGPLにするのが定番なんでしょうか?

    • masuda のコメント:

      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 にしてあるあたりが「法的に絡めて取る」気満々みたいなので、なんかあるとやばそうだなぁという気もしてきますね。

    • masuda のコメント:

      追記、やっぱり Connector は LGPL から GPL に変更されていたのか。
      最初の至高の技を書いたときに LGPL だから、そのままの記憶が orz

  3. C.John のコメント:

    なるほど、昔はLGPLだったんですね。
    初めてMySQLと繋げようとしているので、どうやって実現するか悩み中ですが、Connectorは避けた方が無難ですね。

    ちなみに「抜け道」のやり方はまずいと思います。
    GPLのFAQによると、GPLライブラリを使用して、LGPLでリリースする場合は、GPLにしないといけないようです。
    http://www.gnu.org/licenses/gpl-faq.en.html#AllCompatibility

    • masuda のコメント:

      ちと、亀レスになってしまいましたが。。
      ああ、確かに GPL->LGPLのラップはダメですね。GPLに「汚染される」という形で。

      となると、MySQL+生のADO.NETを使うってのが良さそうに思えたのですが、
      MySQL を含んだアプリを使うときには、結局ライセンス購入が発生するので、
      MySQL+Connector/NETのライセンスをワンセットで購入、というのがベターかもしれませんね。

コメントは停止中です。