방법: 개체 간 관계 변경(Entity Framework)

이 항목에서는 EntityReference 개체를 사용하여 개체 컨텍스트에서 두 개체 간의 관계를 변경하는 방법을 보여 줍니다. SaveChanges 메서드를 호출하면 관계 변경이 데이터베이스에서 관련된 테이블의 외래 키 변경으로 보관됩니다. 또한 이 항목에서는 AssociationChanged 이벤트 처리 방법도 소개합니다.

이 항목의 예제는 Adventure Works Sales 모델을 기반으로 합니다. 이 예제의 코드를 실행하려면 프로젝트에 AdventureWorks Sales 모델을 추가하고 프로젝트에서 엔터티 프레임워크를 사용하도록 구성해야 합니다. 이렇게 하려면 방법: Entity Framework 프로젝트 수동 구성방법: 엔터티 데이터 모델 수동 정의(Entity Framework)의 절차를 수행합니다. 또한 다음 using 문(Visual Basic에서는 Imports)을 코드에 추가해야 합니다.

Imports System.ComponentModel
using System.ComponentModel;

예제

이 예제에서는 EntityReference 개체를 사용하여 SalesOrderHeader 개체와 주문의 배송 주소를 나타내는 관련 Address 개체 사이의 관계를 변경하는 방법을 보여 줍니다.

'Define the order and new address IDs.
Dim orderId As Integer = 43669
Dim newAddressId As Integer = 26

Using context As New AdventureWorksEntities()
    Try
        ' Get the billing address to change to.
        Dim newAddress As Address = context.Address _
            .Where("it.AddressID = @addressId", _
            New ObjectParameter("addressId", newAddressId)) _
        .First()

        ' Get the order being changed.
        Dim order As SalesOrderHeader = context.SalesOrderHeader _
            .Where("it.SalesOrderID = @orderId", _
            New ObjectParameter("orderId", orderId)).First()

        ' Load the current billing address.
        If Not order.Address1Reference.IsLoaded Then
            order.Address1Reference.Load()
        End If

        ' Write the current billing street address.
        Console.WriteLine("Current street: " _
            + order.Address1.AddressLine1)

        ' Change the billing address.
        If Not order.Address1.Equals(newAddress) Then
            order.Address1 = newAddress

            ' Write the changed billing street address.
            Console.WriteLine("Changed street: " _
                + order.Address1.AddressLine1)
        End If

        ' If the address change succeeds, save the changes.
        context.SaveChanges()

        ' Write the current billing street address.
        Console.WriteLine("Current street: " _
            + order.Address1.AddressLine1)
    Catch ex As ApplicationException
        ' Handle the exception raised in the ShippingAddress_Changed 
        ' handler when the status of the order prevents the 
        ' shipping address from being changed. Don't retry because
        ' the relationship is in an inconsistent state and calling 
        ' SaveChanges() will result in an UpdateException.
        Console.WriteLine(ex.ToString())
    Catch ex As InvalidOperationException
        Console.WriteLine(ex.ToString())
    End Try
End Using
// Define the order and new address IDs.
int orderId = 43669;
int newAddressId = 26;

using (AdventureWorksEntities context 
    = new AdventureWorksEntities())
{
    try
    {
        // Get the billing address to change to.
        Address newAddress = context.Address
            .Where("it.AddressID = @addressId",
            new ObjectParameter("addressId", newAddressId))
            .First();

        // Get the order being changed.
        SalesOrderHeader order = context.SalesOrderHeader
            .Where("it.SalesOrderID = @orderId",
            new ObjectParameter("orderId", orderId)).First();

        // Load the current billing address.
        if (!order.Address1Reference.IsLoaded)
        {
            order.Address1Reference.Load();
        }

        // Write the current billing street address.
        Console.WriteLine("Current street: " 
            + order.Address1.AddressLine1);

        // Change the billing address.
        if (!order.Address1.Equals(newAddress))
        {
            order.Address1 = newAddress;

            // Write the changed billing street address.
            Console.WriteLine("Changed street: "
                + order.Address1.AddressLine1);
        }

        // If the address change succeeds, save the changes.
        context.SaveChanges();

        // Write the current billing street address.
        Console.WriteLine("Current street: "
            + order.Address1.AddressLine1);
    }
    catch (ApplicationException ex)
    {
        // Handle the exception raised in the ShippingAddress_Changed 
        // handler when the status of the order prevents the 
        // shipping address from being changed. Don't retry because
        // the relationship is in an inconsistent state and calling 
        // SaveChanges() will result in an UpdateException.
        Console.WriteLine(ex.ToString());
    }
    catch (InvalidOperationException ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

이 예제에서는 이전의 예제를 확장하며, 배송 주소를 나타내는 Address 개체에 대해 EntityReference에서 AssociationChanged 이벤트를 처리하여 주문 상태를 확인하는 방법을 보여 줍니다. 주문 상태가 3보다 클 경우 해당 주문은 변경할 수 없으며 예외가 발생합니다. SalesOrderHeader partial 클래스의 생성자에서 위임이 정의되며, 이 이벤트의 처리기 역시 이 partial 클래스에서 구현됩니다. 따라서 주문의 배송 주소가 바뀔 때마다 주문 상태가 확인됩니다.

SalesOrderHeader-Address 관계의 반대쪽에서 변경의 유효성을 검사하려면 비슷한 방법으로 배송 주소와 관련된 SalesOrderHeader 개체의 EntityCollection에서 AssociationChanged 이벤트를 등록할 수 있습니다.

Partial Public Class SalesOrderHeader
    ' SalesOrderHeader default constructor.
    Public Sub New()
        ' Register the handler for changes to the 
        ' shipping address (Address1) reference.
        AddHandler Me.Address1Reference.AssociationChanged, _
        AddressOf ShippingAddress_Changed
    End Sub

    ' AssociationChanged handler for the relationship 
    ' between the order and the shipping address.
    Private Sub ShippingAddress_Changed(ByVal sender As Object, _
        ByVal e As CollectionChangeEventArgs)
        ' Check for a related reference being removed. 
        If e.Action = CollectionChangeAction.Remove Then
            ' Check the order status and raise an exception if 
            ' the order can no longer be changed.
            If Me.Status > 3 Then
                Throw New ApplicationException( _
                    "The shipping address cannot " _
                + "be changed because the order has either " _
                + "already been shipped or has been cancelled.")
            End If
        End If
    End Sub
End Class
public partial class SalesOrderHeader
{
    // SalesOrderHeader default constructor.
    public SalesOrderHeader()
    {
        // Register the handler for changes to the 
        // shipping address (Address1) reference.
        this.Address1Reference.AssociationChanged
            += new CollectionChangeEventHandler(ShippingAddress_Changed);
    }

    // AssociationChanged handler for the relationship 
    // between the order and the shipping address.
    private void ShippingAddress_Changed(object sender,
        CollectionChangeEventArgs e)
    {
        // Check for a related reference being removed. 
        if (e.Action == CollectionChangeAction.Remove)
        {
            // Check the order status and raise an exception if 
            // the order can no longer be changed.
            if (this.Status > 3)
            {
                throw new ApplicationException(
                    "The shipping address cannot "
                + "be changed because the order has either "
                + "already been shipped or has been cancelled.");
            }
        }
    }
}

참고 항목

기타 리소스

개체 사용(Entity Framework 작업)