다음을 통해 공유


LINQ to SQL의 Serialization

이 문서에서는 LINQ to SQL serialization 기능에 대해 설명합니다. 다음 단락은 디자인 타임에 코드 생성 중에 serialization을 추가하는 방법과 LINQ to SQL 클래스의 런타임 serialization 동작에 대한 정보를 제공합니다.

다음 방법 중 하나를 사용하여 디자인 타임에 serialization 코드를 추가할 수 있습니다.

  • 개체 관계형 디자이너에서 직렬화 모드 속성을 단방향으로 변경합니다.

  • SQLMetal 명령줄에서 /serialization 옵션을 추가합니다. 자세한 내용은 SqlMetal.exe(코드 생성 도구)를 참조하세요.

개요

LINQ to SQL에서 생성된 코드는 기본적으로 지연된 로드 기능을 제공합니다. 지연 로드는 요청 시 데이터의 투명한 로드를 위해 중간 계층에서 매우 편리합니다. 그러나 지연 로드가 의도된 것인지 여부와 관계없이 serializer가 이를 트리거하기 때문에 serialization에는 문제가 있습니다. 실제로 개체가 직렬화되면, 모든 외부로 나가는 지연 로드 참조에 따라 그 전이적 폐쇄도 직렬화됩니다.

LINQ to SQL serialization 기능은 주로 다음 두 가지 메커니즘을 통해 이 문제를 해결합니다.

정의

  • DataContract serializer: .NET Framework 3.0 이상 버전의 WCF(Windows Communication Framework) 구성 요소에서 사용하는 기본 직렬 변환기입니다.

  • 단방향 직렬화: 주기를 방지하기 위해 단방향 연관 속성만을 포함하는 클래스의 직렬화 버전입니다. 관행에 따라 기본 키-외래 키 관계의 부모 쪽에 있는 속성은 직렬화용으로 표시됩니다. 양방향 연결의 다른 쪽은 직렬화되지 않습니다.

    단방향 serialization은 LINQ to SQL에서 지원하는 유일한 직렬화 형식입니다.

코드 예제

다음 코드는 Northwind 샘플 데이터베이스의 기존 Customer 클래스와 Order 클래스를 사용하며 이러한 클래스가 serialization 특성으로 데코레이팅되는 방법을 보여 줍니다.

// The class is decorated with the DataContract attribute.
[Table(Name="dbo.Customers")]
[DataContract()]
public partial class Customer : INotifyPropertyChanging, INotifyPropertyChanged
{
' The class is decorated with the DataContract attribute.
<Table(Name:="dbo.Customers"),  _
 DataContract()>  _
Partial Public Class Customer
    Implements System.ComponentModel.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged
// Private fields are not decorated with any attributes, and are
// elided.
private string _CustomerID;

// Public properties are decorated with the DataMember
// attribute and the Order property specifying the serial
// number. See the Order class later in this topic for
// exceptions.
public Customer()
{
    this.Initialize();
}

[Column(Storage="_CustomerID", DbType="NChar(5) NOT NULL", CanBeNull=false, IsPrimaryKey=true)]
[DataMember(Order=1)]
public string CustomerID
{
    get
    {
        return this._CustomerID;
    }
    set
    {
        if ((this._CustomerID != value))
        {
            this.OnCustomerIDChanging(value);
            this.SendPropertyChanging();
            this._CustomerID = value;
            this.SendPropertyChanged("CustomerID");
            this.OnCustomerIDChanged();
        }
    }
}
' Private fields are not decorated with any attributes,
' and are elided.
Private _CustomerID As String

' Public properties are decorated with the DataMember
' attribute and the Order property specifying the
' serial number. See the Order class later in this topic
' for exceptions
<Column(Storage:="_CustomerID", DbType:="NChar(5) NOT NULL", CanBeNull:=false, IsPrimaryKey:=true),  _
 DataMember(Order:=1)>  _
Public Property CustomerID() As String
    Get
        Return Me._CustomerID
    End Get
    Set
        If ((Me._CustomerID = value)  _
                    = false) Then
            Me.OnCustomerIDChanging(value)
            Me.SendPropertyChanging
            Me._CustomerID = value
            Me.SendPropertyChanged("CustomerID")
            Me.OnCustomerIDChanged
        End If
    End Set
End Property
// The following Association property is decorated with
// DataMember because it is the parent side of the
// relationship. The reverse property in the Order class
// does not have a DataMember attribute. This factor
// prevents a 'cycle.'
[Association(Name="FK_Orders_Customers", Storage="_Orders", OtherKey="CustomerID", DeleteRule="NO ACTION")]
[DataMember(Order=13)]
public EntitySet<Order> Orders
{
    get
    {
        return this._Orders;
    }
    set
    {
        this._Orders.Assign(value);
    }
}
   ' The following Association property is decorated with
   ' DataMember because it is the parent side of the
   ' relationship. The reverse property in the Order
   ' class does not have a DataMember attribute. This
   ' factor prevents a 'cycle.'
   <Association(Name:="FK_Orders_Customers", Storage:="_Orders", OtherKey:="CustomerID", DeleteRule:="NO ACTION"), _
 DataMember(Order:=13)> _
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

다음 예제의 Order 클래스에서는 간단히 하기 위해 클래스에 Customer 해당하는 역방향 연결 속성만 표시됩니다. 주기를 피하기 위한 DataMemberAttribute 특성이 없습니다.

// The class for the Orders table is also decorated with the
// DataContract attribute.
[Table(Name="dbo.Orders")]
[DataContract()]
public partial class Order : INotifyPropertyChanging, INotifyPropertyChanged
' The class for the Orders table is also decorated with the
' DataContract attribute.
<Table(Name:="dbo.Orders"),  _
 DataContract()>  _
Partial Public Class [Order]
    Implements System.ComponentModel.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged
// Private fields for the Orders table are not decorated with
// any attributes, and are elided.
private int _OrderID;

// Public properties are decorated with the DataMember
// attribute.
// The reverse Association property on the side of the
// foreign key does not have the DataMember attribute.
[Association(Name = "FK_Orders_Customers", Storage = "_Customer", ThisKey = "CustomerID", IsForeignKey = true)]
public Customer Customer
' Private fields for the Orders table are not decorated with
' any attributes, and are elided.
Private _CustomerID As String

' Public properties are decorated with the DataMember
' attribute.
' The reverse Association property on the side of the
' foreign key does not have the DataMember attribute.
<Association(Name:="FK_Orders_Customers", Storage:="_Customer", ThisKey:="CustomerID", IsForeignKey:=true)>  _
Public Property Customer() As Customer

엔터티를 직렬화하는 방법

다음과 같이 이전 섹션에 표시된 코드에서 엔터티를 직렬화할 수 있습니다.

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

Customer cust = db.Customers.Where(c => c.CustomerID ==
    "ALFKI").Single();

DataContractSerializer dcs =
    new DataContractSerializer(typeof(Customer));
StringBuilder sb = new StringBuilder();
XmlWriter writer = XmlWriter.Create(sb);
dcs.WriteObject(writer, cust);
writer.Close();
string xml = sb.ToString();
Dim db As New Northwnd("...")

Dim cust = (From c In db.Customers _
            Where c.CustomerID = "ALFKI").Single

Dim dcs As New DataContractSerializer(GetType(Customer))

Dim sb As StringBuilder = New StringBuilder()
Dim writer As XmlWriter = XmlWriter.Create(sb)
dcs.WriteObject(writer, cust)
writer.Close()
Dim xml As String = sb.ToString()

Self-Recursive 관계

자체 재귀 관계는 동일한 패턴을 따릅니다. 외래 키에 해당하는 연결 속성에는 DataMemberAttribute 특성이 없는 반면 부모 속성은 특성이 없습니다.

Employee.Manager/Reports 및 Employee.Mentor/Mentees라는 두 가지 자기 재귀 관계가 있는 클래스를 고려합니다.

// No DataMember attribute.
public Employee Manager;
[DataMember(Order = 3)]
public EntitySet<Employee> Reports;

// No DataMember
public Employee Mentor;
[DataMember(Order = 5)]
public EntitySet<Employee> Mentees;
' No DataMember attribute
Public Manager As Employee
<DataMember(Order:=3)> _
Public Reports As EntitySet(Of Employee)

' No DataMember attribute
Public Mentor As Employee
<DataMember(Order:=5)> _
Public Mentees As EntitySet(Of Employee)

참고하십시오