シリアル化 (LINQ to SQL)
更新 : November 2007
このトピックでは、LINQ to SQL のシリアル化機能について説明します。デザイン時のコード生成でシリアル化を追加する方法と、実行時の LINQ to SQL のクラスのシリアル化の動作について説明します。
デザイン時には、次のいずれかの方法でシリアル化のコードを追加できます。
オブジェクト リレーショナル デザイナで、Serialization Mode プロパティを Unidirectional に変更します。オブジェクト リレーショナル デザイナ (O/R デザイナ)
オブジェクト リレーショナル デザイナー (O/R デザイナー)
オブジェクト リレーショナル デザイナー (O/R デザイナー)SQLMetal コマンド ラインに /serialization オプションを追加します。詳細については、「コード生成ツール (SqlMetal.exe)」を参照してください。
概要
LINQ to SQL が生成するコードには、遅延読み込み機能が既定で備わっています。遅延読み込みは、中間層でデータを必要に応じて透過的に読み込むうえでは非常に便利です。しかし、シリアル化のときには問題です。遅延読み込みが意図されているかどうかに関係なく、シリアライザによって遅延読み込みが発生するためです。具体的には、オブジェクトがシリアル化されるときには、遅延読み込みされるすべての外部参照の推移的閉包がシリアル化されます。
LINQ to SQL のシリアル化機能では、この問題に対処しています。これには主に、次の 2 つの方法が使用されます。
DataContext のモードにより、遅延読み込みをオフにします (ObjectTrackingEnabled)。詳細については、「DataContext」を参照してください。
コード生成のスイッチにより、生成するエンティティに System.Runtime.Serialization.DataContractAttribute 属性および System.Runtime.Serialization.DataMemberAttribute 属性を生成します。この方法と、シリアル化での遅延読み込みクラスの動作が、このトピックの主な話題です。
定義
DataContract シリアライザ : .NET Framework 3.0 以降のバージョンの WCF (Windows Communication Framework) コンポーネントが使用する既定のシリアライザです。
単方向シリアル化 : 循環参照を防ぐために、一方向の関連付けプロパティのみを含む、シリアル化されたバージョンのクラスです。慣例として、主キー/外部キーのリレーションシップの親側のプロパティをシリアル化の対象としてマークします。双方向の関連付けの反対側はシリアル化しません。
LINQ to SQL では、シリアル化の種類として、単方向シリアル化のみがサポートされています。
コード例
次のコードは、Northwind サンプル データベースの典型的な Customer クラスおよび Order クラスを使用して、これらのクラスをシリアル化の属性で装飾するようすを示します。
' The class is decorated with the DataContract attribute.
<Table(Name:="dbo.Customers"), _
DataContract()> _
Partial Public Class Customer
Implements System.ComponentModel.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged
// The class is decorated with the DataContract attribute.
[Table(Name="dbo.Customers")]
[DataContract()]
public partial class Customer : INotifyPropertyChanging, INotifyPropertyChanged
{
' 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
// 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();
}
}
}
' 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
// 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);
}
}
次の例の Order クラスでは、簡略化のために、Customer クラスに関する逆関連付けのプロパティのみを示します。循環参照を防ぐために、DataMember 属性はありません。
' 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
// The class for the Orders table is also decorated with the
// DataContract attribute.
[Table(Name="dbo.Orders")]
[DataContract()]
public partial class Order : INotifyPropertyChanging, INotifyPropertyChanged
' 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
// 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
エンティティをシリアル化する方法
前のセクションで示したコードのエンティティは次のようにシリアル化できます。
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()
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();
自己再帰的リレーションシップ
自己再帰的リレーションシップも同じパターンに従います。外部キーに関する関連付けのプロパティには DataMember 属性がなく、親プロパティにはあります。
次のクラスには、自己再帰的リレーションシップが 2 つあります。Employee.Manager/Reports と Employee.Mentor/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)
// 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;
参照
処理手順
方法 : エンティティをシリアル化可能にする (LINQ to SQL)