かずきのBlog@hatena

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

DLinqで頑張る

DLinqを試す - かずきのBlog@Hatenaの続きだよ。

この間のテーブルにありがちなリレーションをつけてみたよ。
Departmentsテーブルを追加してみたよ。
そして、EmployeesテーブルにはDeptIDっていうカラムを付け足してDepartmentsテーブルに対して外部キーを張ってみたよ。

テストデータはこんな感じで用意してみたよ。
Employeesテーブル

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


Departmentsテーブル

ID Name
1 総務部
2 人事部
3 情報システム部


前回と同じ要領でsqlmetalコマンドで必要なクラスを自動生成してみるね。
そして実験コードを書いてみたよ。

EDU edu = new EDU(@"Server=KAZUKI-PC\SQLEXPRESS;Database=EDU;Integrated Security=true");
edu.Log = Console.Out;

var emps = from emp in edu.Employees
           where emp.ID == 1
           select emp;
foreach (var emp in emps)
{
    Console.WriteLine("Name = {0}", emp.Name);
    Console.WriteLine("DeptName = {0}", emp.Departments.Name);
}

何のことはない、太郎君の名前と部署名を表示するだけだね。
実行してみるよ。

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

Name = 太郎
SELECT [t0].[ID], [t0].[Name]
FROM [Departments] AS [t0]
WHERE [t0].[ID] = @p0
-- @p0: Input Decimal (Size = 0; Prec = 29; Scale = 4) NOT NULL [1]
SqlProvider\AttributedMetaModel

DeptName = 総務部

ログを標準出力に出すようにしてるからちょっとSQL文が邪魔だけど、よく見るとわかるよね?
プログラム中で、emp.Departmentsに初めてアクセスしたタイミングでDepartmentsテーブルに対してのSQL文が発行されているね。
Hibernateを思い出すような動きをしてるよ。


ここで、明示的に一気にDepartmentsテーブルのデータも最初のクエリでとってきたい!というときにはどうするんだろう?
Hibernateでは、明示的にJOINすればよかったから試してみたよ。

EDU edu = new EDU(@"Server=KAZUKI-PC\SQLEXPRESS;Database=EDU;Integrated Security=true");
edu.Log = Console.Out;

var emps = from emp in edu.Employees
           join dept in edu.Departments on emp.DeptID equals dept.ID
           where emp.ID == 1
           select emp;
foreach (var emp in emps)
{
    Console.WriteLine("Name = {0}", emp.Name);
    Console.WriteLine("DeptName = {0}", emp.Departments.Name);
}

実行してみるよ。

SELECT [t0].[ID], [t0].[Name], [t0].[DeptID]
FROM [Employees] AS [t0], [Departments] AS [t1]
WHERE ([t0].[ID] = @p0) AND ([t0].[DeptID] = [t1].[ID])
-- @p0: Input Decimal (Size = 0; Prec = 29; Scale = 4) NOT NULL [1]
SqlProvider\AttributedMetaModel

Name = 太郎
SELECT [t0].[ID], [t0].[Name]
FROM [Departments] AS [t0]
WHERE [t0].[ID] = @p0
-- @p0: Input Decimal (Size = 0; Prec = 29; Scale = 4) NOT NULL [1]
SqlProvider\AttributedMetaModel

DeptName = 総務部

残念な事にSQLが2つ発行されちゃった…
これはこういうものだと思ってあきらめるしかないのかな?


もしくは、ほしいデータだけ匿名クラスで返してもらうようにするか。
下みたいな感じにね。

EDU edu = new EDU(@"Server=KAZUKI-PC\SQLEXPRESS;Database=EDU;Integrated Security=true");
edu.Log = Console.Out;

var emps = from emp in edu.Employees
           where emp.ID == 1
           select new { Name = emp.Name, DeptName = emp.Departments.Name } ;
foreach (var emp in emps)
{
    Console.WriteLine("Name = {0}", emp.Name);
    Console.WriteLine("DeptName = {0}", emp.DeptName);
}

実行結果を見るとSQLが1つだけになってるのが分かると思うよ。

SELECT [t0].[Name], [t1].[Name] AS [Name2]
FROM [Employees] AS [t0], [Departments] AS [t1]
WHERE ([t1].[ID] = [t0].[DeptID]) AND ([t0].[ID] = @p0)
-- @p0: Input Decimal (Size = 0; Prec = 29; Scale = 4) NOT NULL [1]
SqlProvider\AttributedMetaModel

Name = ほげほげ
DeptName = 総務部

当然といえば当然の結果だよね。