方法: データベース リレーションシップを割り当てる

データ リレーションシップが常に同じ場合は、これをエンティティ クラス内のプロパティ参照としてエンコードできます。 たとえば、Northwind サンプル データベースでは、通常は顧客が注文を発注するため、モデルには、顧客と注文のリレーションシップが常に存在します。

LINQ to SQL では、そのようなリレーションシップを表すのに役立つ AssociationAttribute 属性が定義されています。 この属性を、EntitySet<TEntity> 型および EntityRef<TEntity> 型と共に使用することで、データベース内の外部キー リレーションシップが表されます。 詳しくは、「属性ベースの対応付け」の関連付け属性のセクションをご覧ください。

Note

AssociationAttribute プロパティ値と ColumnAttribute Storage プロパティ値では大文字と小文字が区別されます。 たとえば、AssociationAttribute.Storage プロパティの属性に使用されている値は、コード内の別の場所で使用されている対応するプロパティ名と、大文字と小文字が一致するようにしてください。 これは、Visual Basic など、通常は大文字と小文字が区別されない言語を含むすべての .NET プログラミング言語に適用されます。 Storage プロパティの詳細については、「DataAttribute.Storage」を参照してください。

ほとんどのリレーションシップは、このトピックの例のように、一対多のリレーションシップです。 次に示すように、一対一および多対多のリレーションシップも表すことができます。

  • 一対一: 両側で EntitySet<TEntity> を指定することによって、この種類のリレーションシップを表します。

    たとえば、顧客のセキュリティ コードが Customer テーブルにはなく、承認されたユーザーのみがアクセスできるように作成された、Customer-SecurityCode リレーションシップがその例です。

  • 多対多: 多対多リレーションシップでは、リンク テーブル ("結合" テーブルともいいます) の主キーは、多くの場合、他の 2 つのテーブルの外部キーが結合して作成されます。

    たとえば、リンク テーブル Employee を使用して作成される -ProjectEmployeeProject という多対多リレーションシップがあるとします。 LINQ to SQL では、このようなリレーションシップを、EmployeeProjectEmployeeProject という 3 つのクラスを使用してモデル化する必要があります。 この場合、EmployeeProject の間のリレーションシップを変更すると、主キーの EmployeeProject の更新が必要であるように見える可能性がありす。 ただし、この状態は、既存の EmployeeProject の削除、および新しい EmployeeProject の作成として適切にモデル化されます。

    Note

    リレーショナル データベース内のリレーションシップは、通常、他のテーブルの主キーを参照する外部キー値としてモデル化されます。 それらの間を移動するには、リレーショナル "結合" 演算を使用して、2 つのテーブルを明示的に関連付けます。

    これに対し、LINQ to SQL 内のオブジェクトは、"ドット" 表記を使用してナビゲートするプロパティ参照または参照のコレクションを使用して、互いを参照します。

例 1

次の一対多の例では、Customer クラスは、顧客とその注文のリレーションシップを宣言するプロパティを持ちます。 Orders プロパティは EntitySet<TEntity> 型です。 この型は、このリレーションシップが一対多 (1 人の顧客対多くの注文) であることを意味します。 OtherKey プロパティを使用して、この関連付けを実現する方法を記述します。つまり、これと比較する、関連クラス内のプロパティの名前を指定します。 この例では、データベース "結合" でその列の値が比較されるときに、CustomerID プロパティが比較されます。

Note

Visual Studio を使用している場合は、オブジェクト リレーショナル デザイナーを使用して、クラス間の関連付けを作成できます。

[Table(Name = "Customers")]
public partial class Customer
{
    [Column(IsPrimaryKey = true)]
    public string CustomerID;
    // ...
    private EntitySet<Order> _Orders;
    [Association(Storage = "_Orders", OtherKey = "CustomerID")]
    public EntitySet<Order> Orders
    {
        get { return this._Orders; }
        set { this._Orders.Assign(value); }
    }
}
<Table(Name:="Customers")> _
Public Class Customer
    <Column(IsPrimaryKey:=True)> _
    Public CustomerID As String
    ' ...
    Private _Orders As EntitySet(Of Order)
    <Association(Storage:="_Orders", OtherKey:="CustomerID")> _
    Public Property Orders() As EntitySet(Of Order)
        Get
            Return Me._Orders
        End Get
        Set(ByVal value As EntitySet(Of Order))
            Me._Orders.Assign(value)
        End Set
    End Property
End Class

例 2

逆の場合も可能です。 Customer クラスを使用して顧客と注文の関連付けを記述するのではなく、Order クラスを使用できます。 Order クラスは、EntityRef<TEntity> 型を使用して、次のコード例に示すように、顧客へのリレーションシップを記述できます。

Note

EntityRef<TEntity> クラスでは、"遅延読み込み" がサポートされています。 詳細については、「遅延読み込みと即時読み込み」を参照してください

[Table(Name = "Orders")]
public class Order
{
    [Column(IsPrimaryKey = true)]
    public int OrderID;
    [Column]
    public string CustomerID;
    private EntityRef<Customer> _Customer;
    [Association(Storage = "_Customer", ThisKey = "CustomerID")]
    public Customer Customer
    {
        get { return this._Customer.Entity; }
        set { this._Customer.Entity = value; }
    }
}
<Table(Name:="Orders")> _
Public Class Order
    <Column(IsPrimaryKey:=True)> _
    Public OrderID As Integer
    <Column()> _
    Public CustomerID As String
    Private _Customer As EntityRef(Of Customer)
    <Association(Storage:="Customer", ThisKey:="CustomerID")> _
    Public Property Customer() As Customer
        Get
            Return Me._Customer.Entity
        End Get
        Set(ByVal value As Customer)
            Me._Customer.Entity = value
        End Set
    End Property
End Class

関連項目