過去のLINQ to SQLに関して書いた時には気づかなかったことがあった!
http://d.hatena.ne.jp/okazuki/20070422/1177212508
http://d.hatena.ne.jp/okazuki/20070423/1177339579
http://d.hatena.ne.jp/okazuki/20070423/1177339578
http://blogs.wankuma.com/kazuki/archive/2007/08/16/90606.aspx
http://blogs.wankuma.com/kazuki/archive/2007/08/16/90607.aspx
とりあえずおさらいとして、下のような感じに定義したテーブルがあるとする。
create table Departments (
ID int IDENTITY(1,1) primary key,
Name nvarchar(100) not null,
Version timestamp not null);
create table Employees(
ID int IDENTITY(1,1) primary key,
Name nvarchar(100) not null,
Salary int not null,
DeptID int not null,
Version timestamp not null,
constraint FK_EMP_DEPT
foreign key(DeptID) references Departments(ID));
データは↓の表にあるようなのを入れておいた。(Versionカラムは省略)
Departments
ID |
Name |
1 |
総務部 |
2 |
人事部 |
3 |
経理部 |
Employees
ID |
Name |
Salary |
DeptID |
2 |
太郎 |
200000 |
1 |
5 |
二郎 |
250000 |
2 |
6 |
三郎 |
300000 |
3 |
LINQ to SQLクラスをプロジェクトに追加して、テーブルをぽとっと落とす。
ファイル名はEdu.dbmlにしといた。
これに対して、以下のようなプログラムを書いたとする。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LinqToSqlSample.Properties;
namespace LinqToSqlSample
{
class Program
{
static void Main(string[] args)
{
EduDataContext ctx = new EduDataContext(
Settings.Default.EmpMngConnectionString);
ctx.Log = Console.Out; // SQLを標準出力に吐くよ
var emps = from emp in ctx.Employees
select emp;
foreach (var emp in emps)
{
Console.WriteLine("{0}さん {1}部", emp.Name, emp.Departments.Name);
}
}
}
}
これを実行すると下のようにSQL文がやたらいっぱい出てしまう。
これが非常に嫌だった。
SELECT [t0].[ID], [t0].[Name], [t0].[Salary], [t0].[DeptID], [t0].[Version]
FROM [dbo].[Employees] AS [t0]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
SELECT [t0].[ID], [t0].[Name], [t0].[Version]
FROM [dbo].[Departments] AS [t0]
WHERE [t0].[ID] = @p0
-- @p0: Input Int32 (Size = 0; Prec = 0; Scale = 0) [1]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
太郎さん 総務部部
SELECT [t0].[ID], [t0].[Name], [t0].[Version]
FROM [dbo].[Departments] AS [t0]
WHERE [t0].[ID] = @p0
-- @p0: Input Int32 (Size = 0; Prec = 0; Scale = 0) [2]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
二郎さん 人事部部
SELECT [t0].[ID], [t0].[Name], [t0].[Version]
FROM [dbo].[Departments] AS [t0]
WHERE [t0].[ID] = @p0
-- @p0: Input Int32 (Size = 0; Prec = 0; Scale = 0) [3]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
三郎さん 経理部部
これくらいいっぱつでちゃちゃっととってきてほしくて、ちょっと頑張った形跡が過去のエントリの中にあったりする。
結局できなかったけど。
でも、最近やっとやりかたがわかった!!!DataShapeというクラスを使えば解決らしい。
これを読んだら書いてあった。
使い方も簡単。インスタンスを作って、LoadWithを呼べばいいと書いてある。
早速実験!!!さっきのコードに赤字の部分を付け足して見た。
…DataShapeっていうクラス自体が見当たらない!?何でだろう?と考えてそれっぽいクラスを探して見たらあった。
DataOptionsという風に名前が変わってたっぽい。さすがBeta。気を取り直して赤字の部分を付け足して実行してみた。
プログラム
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LinqToSqlSample.Properties;
using System.Data.Linq;
namespace LinqToSqlSample
{
class Program
{
static void Main(string[] args)
{
EduDataContext ctx = new EduDataContext(
Settings.Default.EmpMngConnectionString);
ctx.Log = Console.Out;
// Employesと一緒にDepartmentsも読み込んでね
DataLoadOptions ops = new DataLoadOptions();
ops.LoadWith<Employees>(e => e.Departments);
ctx.LoadOptions = ops;
var emps = from emp in ctx.Employees
select emp;
foreach (var emp in emps)
{
Console.WriteLine("{0}さん {1}部", emp.Name, emp.Departments.Name);
}
}
}
}
実行結果
SELECT [t0].[ID], [t0].[Name], [t0].[Salary], [t0].[DeptID], [t0].[Version], [t1].[ID] AS [ID2], [t1].[Name] AS [Name2], [t1].[Version] AS [Version2]
FROM [dbo].[Employees] AS [t0]
INNER JOIN [dbo].[Departments] AS [t1] ON [t1].[ID] = [t0].[DeptID]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
太郎さん 総務部部
二郎さん 人事部部
三郎さん 経理部部
おおおお!ちゃんと1回のクエリでとってきてる!!
こうやって指定するのかぁ。メモメモ。