방법: 데이터베이스 관계 매핑

항상 동일하게 유지되는 모든 데이터 관계를 엔터티 클래스에서 속성 참조로 인코딩할 수 있습니다. 예를 들어 Northwind 샘플 데이터베이스에서는 일반적으로 고객이 주문을 하기 때문에 고객과 고객 주문 간의 관계가 항상 모델에 존재합니다.

LINQ to SQL은 이러한 관계를 나타내는 데 도움이 되는 AssociationAttribute 특성을 정의합니다. 이 특성은 데이터베이스에서의 외래 키 관계가 무엇인지 나타내기 위해 EntitySet<TEntity>EntityRef<TEntity> 형식과 함께 사용됩니다. 자세한 내용은 특성 기반 매핑의 연결 특성 섹션을 참조하세요.

참고 항목

AssociationAttribute 및 ColumnAttribute Storage 속성 값은 대/소문자를 구분합니다. 예를 들어 AssociationAttribute.Storage 속성의 특성에 사용하는 값은 코드의 다른 곳에서 사용하는 해당 속성 이름과 대/소문자가 동일해야 합니다. 이는 Visual Basic을 포함하여 일반적으로 대/소문자를 구분하지 않는 언어를 포함하여 모든 .NET 프로그래밍 언어에 적용됩니다. Storage 속성에 대한 자세한 내용은 DataAttribute.Storage를 참조하세요.

이 항목의 뒷부분에 나오는 예제처럼 대부분의 관계는 일대다입니다. 다음과 같이 일대일 및 다대다 관계를 나타낼 수도 있습니다.

  • 일대일: 양쪽 모두에 EntitySet<TEntity>을 포함하여 이 종류의 관계를 나타냅니다.

    고객의 보안 코드를 Customer 테이블에서 찾을 수 없고 인증된 사람만 액세스할 수 있도록 만들어진 Customer-SecurityCode 관계를 예로 들 수 있습니다.

  • 다대다: 다대다 관계에서 링크 테이블(접합 테이블)의 기본 키는 일반적으로 다른 두 테이블의 외래 키 조합으로 구성됩니다.

    예를 들어 EmployeeProject 링크 테이블을 사용하여 구성된 Employee-Project 다대다 관계가 있다고 가정해 봅니다. LINQ to SQL에서는 Employee, ProjectEmployeeProject의 세 가지 클래스를 사용하여 이러한 관계를 모델링해야 합니다. 이 경우 EmployeeProject 간의 관계를 변경하려면 기본 키 EmployeeProject의 업데이트가 필요한 것처럼 보일 수 있습니다. 그러나 이 상황을 모델링하는 최선의 방법은 기존 EmployeeProject를 삭제하고 새 EmployeeProject를 만드는 것입니다.

    참고 항목

    관계형 데이터베이스에서 관계는 일반적으로 다른 테이블의 기본 키를 참조하는 외래 키 값으로 모델링됩니다. 이러한 키 사이를 탐색하려면 관계형 조인 작업을 사용하여 두 테이블을 명시적으로 연결합니다.

    반면에 LINQ to SQL의 개체는 속성 참조 또는 표기법을 사용하여 탐색하는 참조 컬렉션을 사용하여 서로를 참조하세요.

예 1

다음 일대다 예제에서 Customer 클래스는 고객과 고객의 주문 사이의 관계를 선언하는 속성을 가집니다. Orders 속성은 EntitySet<TEntity> 형식입니다. 이 형식은 이 관계가 일대다(한 명의 고객과 여러 개의 주문)라는 것을 나타냅니다. OtherKey 속성은 이 속성과 비교할 관련 클래스의 속성 이름을 지정함으로써 이 연결이 이루어지는 방법을 설명하는 데 사용됩니다. 이 예에서는 데이터베이스 조인이 해당 열 값을 비교하는 것처럼 CustomerID 속성이 비교됩니다.

참고 항목

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> 형식을 사용하여 고객에 대한 관계를 설명합니다.

참고 항목

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

참고 항목