LINQ to SQL의 serialization
이 문서에서는 LINQ to SQL serialization 기능에 대해 설명합니다. 디자인 타임에 코드 생성 도중 serialization을 추가하는 방법과 LINQ to SQL 클래스의 런타임 serialization 동작에 대한 정보가 제공됩니다.
다음 방법 중 하나로 디자인 타임에 serialization 코드를 추가할 수 있습니다.
개체 관계형 디자이너에서 serialization 모드 속성을 단방향으로 변경합니다.
SQLMetal 명령줄에서 /serialization 옵션을 추가합니다. 자세한 내용은 SqlMetal.exe(코드 생성 도구)를 참조하세요.
개요
LINQ to SQL에 의해 생성된 코드는 기본적으로 지연된 로드 기능을 제공합니다. 지연된 로드를 사용하면 중간 계층에서 매우 편리하게 데이터를 필요한 때 투명하게 로드할 수 있습니다. 그러나 지연된 로드를 원하는지 여부에 상관없이 serializer가 지연된 로드를 트리거하기 때문에 이것은 serialization에서 문제가 됩니다. 실제로 개체가 serialize될 때 모든 지연 로드된 아웃바운드 참조 아래의 전이적 닫기가 serialize됩니다.
serialization 기능은 주로 다음과 같은 두 개의 메커니즘을 통해 이 문제를 해결합니다.
지연된 로드를 해제하기 위한 DataContext 모드(ObjectTrackingEnabled). 자세한 내용은 DataContext를 참조하세요.
생성된 엔터티에서 System.Runtime.Serialization.DataContractAttribute 및 System.Runtime.Serialization.DataMemberAttribute 특성을 생성하기 위한 코드 생성 스위치. serialization 아래의 지연 로드 클래스 동작을 비롯한 이 개념이 이 항목의 주제입니다.
정의
DataContract serializer: NET Framework 3.0 이상 버전의 WCF(Windows Communication Framework) 구성 요소에 사용되는 기본 serializer입니다.
단방향 serialization: 순환을 방지하기 위해 단방향 연결 속성만 포함하는 클래스의 serialize된 버전입니다. 규칙에 따라 기본 및 외래 키 관계의 부모 쪽에 대한 속성이 serialization용으로 표시됩니다. 양방향 연결의 다른 쪽은 serialize되지 않습니다.
단방향 serialization은 LINQ to SQL에서 지원되는 유일한 serialization 형식입니다.
코드 예
다음 코드에서는 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
엔터티를 Serialize하는 방법
다음과 같이 앞 단원에 나온 코드의 엔터티를 serialize할 수 있습니다.
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()
자체 재귀적 관계
자체 재귀적 관계는 동일한 패턴을 따릅니다. 외래 키에 해당하는 연결 속성에는 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)