かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

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にアクセスしにいくっぽい。
ここら辺の動きをおさえておかないと、何かはまっちゃうかもしれないね。
でも、今日はここまで。