リレーションシップを介したクエリの実行

他のオブジェクトまたは他のオブジェクトのコレクションをクラス定義内で参照することは、データベース内の外部キー リレーションシップに直接対応します。 クエリを実行するときにこのリレーションシップを使用するには、ドット表記を使ってリレーションシップ プロパティにアクセスし、オブジェクト間を移動します。 これらのアクセス操作は、SQL で同等の複雑な結合または相関サブクエリとして変換されます。

たとえば、次のクエリでは、ロンドン在住の顧客からの注文のみが結果として得られるように注文から顧客へと移動します。

        Northwnd db = new Northwnd(@"northwnd.mdf");

        IQueryable<Order> londonOrderQuery =
from ord in db.Orders
where ord.Customer.City == "London"
select ord;
    Dim db As New Northwnd("c:\northwnd.mdf")
    Dim londonOrderQuery = _
From ord In db.Orders _
Where ord.Customer.City = "London" _
Select ord

リレーションシップのプロパティが存在しない場合は、SQL クエリの場合と同じように "結合" として、手動で記述する必要があります。次にコードの例を示します。

        Northwnd db = new Northwnd(@"northwnd.mdf");
        IQueryable<Order> londonOrderQuery =
from cust in db.Customers
join ord in db.Orders on cust.CustomerID equals ord.CustomerID
where cust.City == "London"
select ord;
    Dim db As New Northwnd("c:\northwnd.mdf")
    Dim londOrderQuery = _
From cust In db.Customers _
Join ord In db.Orders On cust.CustomerID Equals ord.CustomerID _
Select ord

"リレーションシップ" のプロパティを使用すると、このようなリレーションシップを一度で定義できます。 こうすると、使いやすいドット構文を使用できるようになります。 しかし、それだけがリレーションシップ プロパティの利点ではありません。なぜなら、通常はドメイン固有のオブジェクト モデルは階層構造またはグラフとして定義されるからです。 プログラムで使用するオブジェクトには他のオブジェクトへの参照が含まれます。 このオブジェクト間リレーションシップがデータベースの外部キー型リレーションシップに相当するのは、単なる幸運な偶然です。 プロパティへのアクセスは、結合を記述するための便利な方法となります。

この点では、リレーションシップ プロパティは、クエリそのものよりもクエリの結果でより重要です。 クエリによって特定の顧客に関するデータが取得された後で、クラス定義ではその顧客の注文が存在することが示されます。 つまり、特定の顧客の Orders プロパティにその顧客のすべての注文が含まれると見なすことができます。 実際には、これはクラスをこのように定義することにより宣言したコントラクトです。 クエリによって注文が要求されなかった場合でも、ここに注文が含まれていると見なすことができます。 オブジェクト モデルに対して期待されるのは、それがデータベースがメモリ内に拡張されたものであり、関連オブジェクトがすぐに使用できる状態にある、という錯覚を維持することです。

リレーションシップが得られたので、クラスに定義されたリレーションシップ プロパティを参照してクエリを作成できます。 これらのリレーションシップ参照は、データベース内の外部キー リレーションシップに対応します。 これらのリレーションシップを使用する操作は、SQL で同等の複雑な結合として変換されます。 AssociationAttribute 属性を使用してリレーションシップを定義している限りは、明示的な結合を LINQ to SQL で記述する必要はありません。

この錯覚を維持するために、LINQ to SQL には "遅延読み込み" と呼ばれる機能が実装されています。 詳細については、「遅延読み込みと即時読み込み」を参照してください。

CustomerID-OrderID ペアのリストを投影する次のような SQL クエリがあるとします。

SELECT t0.CustomerID, t1.OrderID  
FROM   Customers AS t0 INNER JOIN  
          Orders AS t1 ON t0.CustomerID = t1.CustomerID  
WHERE  (t0.City = @p0)  

LINQ to SQL を使用して同じ結果を得るには、Customer クラスに既に存在する Orders プロパティ参照を使用します。 次のコードに示すとおり、Orders の参照からは、クエリを実行し、CustomerID-OrderID ペアを投影するために必要な情報が提供されます。

        Northwnd db = new Northwnd(@"northwnd.mdf");
        var idQuery =
from cust in db.Customers
from ord in cust.Orders
where cust.City == "London"
select new { cust.CustomerID, ord.OrderID };
    Dim db As New Northwnd("c:\northwnd.mdf")
    Dim idQuery = _
From cust In db.Customers, ord In cust.Orders _
Where cust.City = "London" _
Select cust.CustomerID, ord.OrderID

逆の操作も可能です。 つまり、Orders にクエリを実行し、その Customer リレーションシップ参照を使用して、関連付けられた Customer オブジェクトに関する情報にアクセスできます。 次のコードでは、前の例と同じ CustomerID-OrderID ペアが投影されますが、ここでは Customers ではなく Orders のクエリを実行しています。

        Northwnd db = new Northwnd(@"northwnd.mdf");
        var idQuery =
from ord in db.Orders
where ord.Customer.City == "London"
select new { ord.Customer.CustomerID, ord.OrderID };
    Dim db As New Northwnd("c:\northwnd.mdf")
    Dim idQuery = _
From ord In db.Orders _
Where ord.Customer.City = "London" _
Select ord.CustomerID, ord.OrderID

関連項目