LINQ to SQLを使ってみる

.NET3.5から追加されたLINQ、そのSQLアクセス用であるLINQ to SQLをさわってみた。

LINQ to SQLを使用する
を見てみると、今までのADO.NETとは違いO/Rマッピングフレームワークになっているのがよくわかる。

データベースの作成

「HogeService」という名前でデータベースを作り、テーブルは以下のように定義。

Customer
列名 備考
ID int PK, NOT NULL, IDENTITY
Name varchar(50) NOT NULL
Product
列名 備考
ID int PK, NOT NULL, IDENTITY
Name varchar(50) NOT NULL
CustomerID int
リレーション
Customer Product
ID CustomerID

それぞれのテーブルに適当にデータを突っ込む。

Customer
ID Name
1 ジョン
2 ポール
3 シンディ
4 キャサリン
5 ドン
Product
ID Name CustomerID
1 テレビ 5
2 ビデオ 4
3 時計 3
4 iPod 2
5 ニップレス 1

プロジェクトの作成

Visual Studio 2008 Beta2 を使用する。
まずは「ConsoleApplication」プロジェクトを作成する。プロジェクトに新しいアイテムとして「LINQ to SQL Classes」を追加する。ファイル名は「HogeService.dbml」とする。

「サーバーエクスプローラー」を開いて、先程作成したデータベースを追加する。そこから「Product」と「Customer」テーブルを「HogeService.dbml」のデザイナ上にDrag&Dropする。

これで列定義をプロパティとして持つ「Product」と「Customer」クラスが自動的に作られる。

いざLINQ

これでLINQ to SQLを使う準備ができたので、まずは「Product」のデータを全件検索してみる。

class Program {
    static void Main() {
        HogeServiceDataContext db = new HogeServiceDataContext();

        var resultSet = from product in db.Products
                        select product;

        foreach(var product in resultSet) {
            Console.WriteLine(
                "ID={0}, Name={1}, Customer={2}", product.ID, product.Name, product.Customer.Name
            );
        }
        Console.Read();
    }
}

「HogeService.dbml」を作ると「HogeServiceDataContext」というクラスが作られる。
LINQ to SQLではこのクラスに対して各種CRUD操作を行う。

まずはこのクラスをインスタンス化する。ちなみにDBへの接続情報はアプリケーション構成ファイルに定義されている。「Product」テーブルに対して検索を行うので、「HogeServiceDataContext」の「Products」プロパティに対してLINQクエリを発行する。出力結果は以下。

ID=1, Name=テレビ, Customer=ドン
ID=2, Name=ビデオ, Customer=キャサリン
ID=3, Name=時計, Customer=シンディ
ID=4, Name=iPod, Customer=ポール
ID=5, Name=ニップレス, Customer=ジョン

驚いた事に「Product」テーブルと「Customer」テーブルがリレーションを張っている事で自動的に「Product」クラスには「Customer」型の「Customer」プロパティが作られている。すげー!!

次はちょっと検索条件を変えてみる。

class Program {
    static void Main() {
        HogeServiceDataContext db = new HogeServiceDataContext();

        var resultSet = from product in db.Products
                        where product.Name.Contains("ビ")
                        orderby product.Customer.ID
                        select product;

        foreach(var product in resultSet) {
            Console.WriteLine(
                "ID={0}, Name={1}, Customer={2}", product.ID, product.Name, product.Customer.Name
            );
        }
        Console.Read();
    }
}

「Product」の「Name」プロパティに"ビ"を含むものを検索して、「Customer」の「ID」でソートする。

ID=2, Name=ビデオ, Customer=キャサリン
ID=1, Name=テレビ, Customer=ドン

すげー!!!!!!!!!!!!!

いままでDAOとかしこしこ作ってたけど、そういうのが全くいらなくなる。ここまで簡単に使えるとiBatis.NETとかNHibernateとかはもう使う気になれない。設定ファイルとか一切いらんもん。

一般的なO/Rマッピングツールのマッピング方法としては、

  1. 設定ファイル(iBatis.NET、NHibernate
  2. 属性ベース(ActiveRecordなんかあるやろ)
  3. コーディング規約(Ruby on Railsのやつ)

で、LINQ to SQLは「IDEによるコード生成」というわけだ(生成されたソースを見たら実際には属性ベースやった)

ちなみに

自動生成されたコードを見てみると

partial void OnCreated();
partial void InsertProduct(Product instance);
partial void UpdateProduct(Product instance);
partial void DeleteProduct(Product instance);
partial void InsertCustomer(Customer instance);
partial void UpdateCustomer(Customer instance);
partial void DeleteCustomer(Customer instance);

というのがあった。

パーシャルメソッドで各CRUD操作時にユーザ定義の処理を埋め込めるようになっている。
今までならこの手のやつはクラスを継承して「On〜」というのをオーバーライドするかイベントにイベントハンドラを追加していたけど、これならいちいちクラスを継承しなくても、パーシャルクラスを作ればいいだけなのですごく便利。パーシャルメソッドの使い道がいまいち不明やったけど、これでわかった。

気になるのはLINQ to SQLで実際にどんなSQLが発行されるのかということ。これはあとで調べる。