かずきのBlog@hatena

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

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 = 総務部

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