Serialización (LINQ to SQL)
Actualización: November 2007
En este tema se describe la funcionalidad de serialización de LINQ to SQL. En los párrafos siguientes se proporciona información sobre cómo agregar la característica de serialización durante la generación de código en tiempo de diseño y el comportamiento de serialización en tiempo de ejecución de las clases LINQ to SQL.
Puede agregar código de serialización en tiempo de diseño mediante cualquiera de estos métodos:
En el Diseñador relacional de objetos, cambie la propiedad Modo de serialización a Unidirectional.
En la línea de comandos de SQLMetal, agregue la opción /serialization. Para obtener más información, vea Herramienta de generación de código (SqlMetal.exe).
Información general
El código generado por LINQ to SQL proporciona funcionalidad de carga aplazada de forma predeterminada. La carga aplazada es muy apropiada en el nivel intermedio, para una carga de datos transparente a petición. Sin embargo, da problemas para la serialización, porque el serializador activa la carga aplazada esté prevista o no. De hecho, cuando se serializa un objeto, se serializa su cierre transitivo en todas las referencias con carga aplazada salientes.
La característica de serialización de LINQ to SQL resuelve este problema, principalmente a través de dos mecanismos:
Un modo DataContext para desactivar la carga aplazada (ObjectTrackingEnabled). Para obtener más información, consulte DataContext.
Un modificador de generación de código para generar los atributos System.Runtime.Serialization.DataContractAttribute y System.Runtime.Serialization.DataMemberAttribute en las entidades generadas. Este aspecto, que incluye el comportamiento de la carga aplazada de las clases en la serialización, es el asunto principal de este tema.
Definiciones
Serializador DataContract: serializador predeterminado utilizado por el componente WCF de .NET Framework 3.0 o versiones posteriores.
Serialización unidireccional: versión serializada de una clase que contiene sólo una propiedad de asociación unidireccional (para evitar un ciclo). Por convención, se marca para la serialización la propiedad que se encuentra en el lado primario de una relación de clave externa y clave principal. No se serializa el otro lado en una asociación bidireccional.
La serialización unidireccional es el único tipo de serialización que LINQ to SQL admite.
Ejemplo de código
El código siguiente utiliza las clases Customer y Order tradicionales de la base de datos de ejemplo Northwind y muestra cómo estas clases se decoran con atributos de serialización.
' 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);
}
}
Para la clase Order del ejemplo siguiente, por brevedad sólo se muestra la propiedad de asociación inversa que corresponde a la clase Customer. No tiene un atributo DataMember para evitar un ciclo.
' 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
Cómo serializar entidades
Puede serializar las entidades del código que se incluía en la sección anterior de la manera siguiente:
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();
Relaciones auto-recursivas
Las relaciones auto-recursivas siguen el mismo modelo. La propiedad de asociación que corresponde a la clave externa no tiene un atributo DataMember, mientras que la propiedad primaria sí lo tiene.
Considere la clase siguiente, que tiene dos relaciones auto-recursivas: Employee.Manager/Reports y 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;
Vea también
Tareas
Cómo: Convertir entidades en serializables (LINQ to SQL)
Referencia
Herramienta de generación de código (SqlMetal.exe)