Serializzazione (LINQ to SQL)
In questo argomento vengono descritte le funzionalità di serializzazione LINQ to SQL. Nei paragrafi che seguono sono disponibili informazioni sull'aggiunta di serializzazione durante la generazione di codice in fase di progettazione e il comportamento di serializzazione delle classi LINQ to SQL in fase di esecuzione.
È possibile aggiungere codice di serializzazione in fase di progettazione utilizzando uno dei metodi seguenti:
In Object Relational Designer impostare la proprietà Serialization Mode su Unidirectional. Per ulteriori informazioni, vedere Progettazione relazionale oggetti e Progettazione relazionale oggetti e Progettazione relazionale oggetti.
Sulla riga di comando SQLMetal aggiungere l'opzione /serialization. Per ulteriori informazioni, vedere SqlMetal.exe (strumento per la generazione del codice).
Panoramica
Il codice generato da LINQ to SQL fornisce funzionalità di caricamento posticipato per impostazione predefinita. Il caricamento posticipato è molto pratico al livello intermedio per il caricamento trasparente dei dati su richiesta, tuttavia risulta problematico per la serializzazione, in quanto il serializzatore attiva comunque il caricamento posticipato a prescindere che questo sia o meno il comportamento designato. In effetti, quando un oggetto è serializzato, viene serializzata la relativa chiusura transitiva in tutti i riferimenti in uscita con caricamento posticipato.
La funzionalità di serializzazione di LINQ to SQL consente di risolvere questo problema, principalmente tramite due meccanismi:
Una modalità DataContext per la disattivazione del caricamento posticipato (ObjectTrackingEnabled). Per ulteriori informazioni, vedere DataContext.
Un'opzione di generazione di codice per generare attributi System.Runtime.Serialization.DataContractAttribute e System.Runtime.Serialization.DataMemberAttribute sulle entità generate. Questo aspetto, incluso il comportamento delle classi a caricamento posticipato sottoposte a serializzazione, è l'oggetto principale di questo argomento.
Definizioni
Serializzatore DataContract: è il serializzatore predefinito utilizzato dal componente Windows Communication Framework (WCF) di .NET Framework 3.0 o versioni successive.
Serializzazione unidirezionale: è la versione serializzata di una classe che contiene solo una proprietà di associazione unidirezionale per evitare un ciclo. Per convenzione, la proprietà sul lato padre di una relazione di chiave primaria-esterna è contrassegnata per la serializzazione. L'altro lato in un'associazione bidirezionale non è serializzato.
La serializzazione unidirezionale è il solo tipo di serializzazione supportato da LINQ to SQL.
Esempio di codice
Nel codice seguente vengono utilizzate le classi Customer e Order tradizionali del database di esempio Northwind e viene descritto in che modo queste classi vengono decorate con gli attributi di serializzazione.
' 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);
}
}
Per la classe Order nell'esempio seguente viene illustrata per brevità solo la proprietà di associazione inversa che corrisponde alla classe Customer. Questa classe non dispone di un attributo DataMember per evitare 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
Come serializzare le entità
È possibile serializzare le entità nei codici riportati nella sezione precedente come segue:
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();
Relazioni autoricorsive
Le relazioni autoricorsive seguono lo stesso modello. La proprietà di associazione che corrisponde alla chiave esterna non dispone di un attributo DataMember, che invece è disponibile nella proprietà padre.
Considerare la classe seguente che dispone di due relazioni autoricorsive: Employee.Manager/Reports e 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;
Vedere anche
Attività
Procedura: creare entità serializzabili (LINQ to SQL)
Riferimenti
SqlMetal.exe (strumento per la generazione del codice)