次の方法で共有


シリアル化 (LINQ to SQL)

このトピックでは、LINQ to SQL のシリアル化機能について説明します。 デザイン時のコード生成でシリアル化を追加する方法と、実行時の LINQ to SQL のクラスのシリアル化の動作について説明します。

デザイン時には、次のいずれかの方法でシリアル化のコードを追加できます。

概要

LINQ to SQL が生成するコードには、遅延読み込み機能が既定で備わっています。 遅延読み込みは、中間層でデータを必要に応じて透過的に読み込むうえでは非常に便利です。 しかし、シリアル化のときには問題です。遅延読み込みが意図されているかどうかに関係なく、シリアライザーによって遅延読み込みが発生するためです。 具体的には、オブジェクトがシリアル化されるときには、遅延読み込みされるすべての外部参照の推移的閉包がシリアル化されます。

LINQ to SQL のシリアル化機能では、この問題に対処しています。これには主に、次の 2 つの方法が使用されます。

定義

  • 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)

参照

SqlMetal.exe (コード生成ツール)

その他の技術情報

背景情報 (LINQ to SQL)