かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

DLinqを試す

DBへの問い合わせにはDLinqというキーワードで色々調べればいいんだって。
ってことで調べてみたよ。


まず、DBを用意しないと始まらないのでSQL Server 2005 Express Editionで下の絵のようなテーブルを作ったよ。

中身のデータは以下のようなものを詰め込んどいたよ。

ID Name
1 太郎
2 二郎
3 三郎
4 四郎
5 五郎


DLinqで使うためのクラスは、ツールが自動生成してくれるみたいだ。
SqlMetal.exeというものらしいよ。
どこにあるのか検索してみたら、Visual Studio OrcasのインストールフォルダのSDK\v3.5\Binにあったよ。
とりあえず、毎回長いパスをうつのがめんどくさいからパスを通しておいた。


sqlmetalとだけ打ち込むと使い方が出てくる。

Sqlmetal [options] [<input file>]
options:
  /server:<name>     Database server name
  /database:<name>   Database catalog on server
  /user:<name>       Login user ID
  /password:<name>   Login password
  /views             Extract database views
  /functions         Extract database functions
  /sprocs            Extract stored procedures
  /xml[:file]        Output as DBML
  /code[:file]       Output as source code
  /map[:file]        Generate XML mapping file instead of attributes
  /language:xxx      Language for source code (vb,csharp)
  /namespace:<name>  Namespace used for source code
  /pluralize         Auto-pluralize table names
  /serialization:xxx Generate serializable classes (None, Unidirectional)
  /timeout:<seconds> Timeout value in seconds to use for database commands

examples:
To generate a .dbml file with extracted SQL metadata.
  Sqlmetal /server:myserver /database:northwind /xml:mymeta.dbml

To generate a .dbml file with extracted SQL metadata from an .mdf file.
  Sqlmetal /xml:mymeta.dbml mydbfile.mdf

To generate source code from a .dbml metadata file.
  Sqlmetal /namespace:nwind /code:nwind.cs /language:csharp mymetal.dbml

To generate source code from SQL metadata directly.
  Sqlmetal /server:myserver /database:northwind /namespace:nwind /code:nwind.cs /language:csharp

色々出てるけど、最後の奴を自分の環境に置き換えてやればよさそうだね。
ということで自分の環境だと下のようにうつとうまくいったよ。

sqlmetal /server:KAZUKI-PC\SQLEXPRESS /database:EDU /namespace:DLinqSample /code:DLinqSample.cs /language:csharp

これでDLinqSample.csが出来上がるから、Visual Studioで作ったプロジェクト(お試しなのでコンソールにしたよ)に追加してビルドしてみるとコンパイルエラーが出ちゃった。
どうやらSystem.Data.Linqを参照に追加しないといけないようだ。

参照を追加したらビルドが通ったので、下のようなプログラムを書いてみたよ。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DLinqSample
{
    class Program
    {
        static void Main(string[] args)
        {
            EDU edu = new EDU(@"Server=KAZUKI-PC\SQLEXPRESS;Database=EDU;Integrated Security=true");
            IEnumerable<Employees> emps = from emp in edu.Employees
                                          where emp.ID % 2 == 0
                                          select emp;
            foreach (Employees emp in emps)
            {
                Console.WriteLine("{0}: {1}", emp.ID, emp.Name);
            }
        }
    }
}

EDUってのは、さっきツールが自動生成してくれたクラスだよ。
これに対して接続文字列かIDbConnectionを渡すことが出来る。
今回は接続文字列を直接指定したよ。


実行してみると、↓みたいな結果だったよ。

2: 二郎
4: 四郎

うん。ちゃんと動いてる。


もう少しだけ踏み込んでみるね。
EDUクラスの親クラスはSystem.Data.Linq.DataContextなんだけど、そいつにはLogってプロパティがあるんだ。
TextWriterを受け取るみたいなので、Console.Outを渡すように書き換えてみたよ。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DLinqSample
{
    class Program
    {
        static void Main(string[] args)
        {
            EDU edu = new EDU(@"Server=KAZUKI-PC\SQLEXPRESS;Database=EDU;Integrated Security=true");
            edu.Log = Console.Out;
            Console.WriteLine("Before LINQ");
            IEnumerable<Employees> emps = from emp in edu.Employees
                                          where emp.ID % 2 == 0
                                          select emp;
            Console.WriteLine("After LINQ");
            foreach (Employees emp in emps)
            {
                Console.WriteLine("{0}: {1}", emp.ID, emp.Name);
            }
        }
    }
}

LINQの直前と直後に目印のログを吐くように仕込んで実行してみたよ。

Before LINQ
After LINQ
SELECT [t0].[ID], [t0].[Name]
FROM [Employees] AS [t0]
WHERE ([t0].[ID] % @p0) = @p1
-- @p0: Input Decimal (Size = 0; Prec = 29; Scale = 4) NOT NULL [2]
-- @p1: Input Decimal (Size = 0; Prec = 29; Scale = 4) NOT NULL [0]
SqlProvider\AttributedMetaModel

2: 二郎
4: 四郎

うん。何か思ったのと出力順が違うね。
DLINQは、必要になった時点ではじめてDBにアクセスしにいくっぽい。
ここら辺の動きをおさえておかないと、何かはまっちゃうかもしれないね。
でも、今日はここまで。