Serialisatie in LINQ naar SQL
In dit artikel worden LINQ-mogelijkheden voor SQL-serialisatie beschreven. De volgende alinea's bevatten informatie over het toevoegen van serialisatie tijdens het genereren van code tijdens het ontwerpen en het serialisatiegedrag van LINQ aan SQL-klassen.
U kunt serialisatiecode toevoegen tijdens het ontwerp door een van de volgende methoden:
Wijzig in de object-relationele ontwerpfunctie de eigenschap Serialisatiemodus in Unidirectioneel.
Voeg op de OPDRACHTREGEL van SQLMetal de optie /serialisatie toe. Zie SqlMetal.exe (hulpprogramma voor het genereren van code) voor meer informatie.
Overzicht
De code die door LINQ naar SQL wordt gegenereerd, biedt standaard uitgestelde laadmogelijkheden. Uitstellen van laden is erg handig op de middellaag voor het transparant laden van gegevens op aanvraag. Het is echter problematisch voor serialisatie, omdat de serialisatiefunctie het uitstellen van het laden activeert, ongeacht of uitstel laden is bedoeld of niet. Wanneer een object wordt geserialiseerd, wordt de transitieve sluiting onder alle uitgaande, uitgestelde verwijzingen geserialiseerd.
Met de functie LINQ naar SQL-serialisatie wordt dit probleem opgelost, voornamelijk via twee mechanismen:
Een DataContext modus voor het uitschakelen van uitgesteld laden (ObjectTrackingEnabled). Zie DataContext voor meer informatie.
Een switch voor het genereren van code om kenmerken voor gegenereerde entiteiten te genereren System.Runtime.Serialization.DataContractAttribute System.Runtime.Serialization.DataMemberAttribute . Dit aspect, met inbegrip van het gedrag van klassen voor uitstellen bij serialisatie, is het belangrijkste onderwerp van dit onderwerp.
Definities
DataContract serializer: Standaardserialisatie die wordt gebruikt door het WCF-onderdeel (Windows Communication Framework) van de .NET Framework 3.0- of latere versies.
Unidirectionele serialisatie: de geserialiseerde versie van een klasse die slechts een eenzijdige koppelingseigenschap bevat (om een cyclus te voorkomen). De eigenschap aan de bovenliggende zijde van een primaire-refererende-sleutelrelatie wordt standaard gemarkeerd voor serialisatie. De andere kant in een bidirectionele koppeling wordt niet geserialiseerd.
Unidirectionele serialisatie is het enige type serialisatie dat wordt ondersteund door LINQ naar SQL.
Codevoorbeeld
De volgende code maakt gebruik van de traditionele Customer
en Order
klassen uit de Northwind-voorbeelddatabase en laat zien hoe deze klassen zijn ingericht met serialisatiekenmerken.
// 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
Voor de Order
klasse in het volgende voorbeeld wordt alleen de eigenschap omgekeerde koppeling weergegeven die overeenkomt met de Customer
klasse. Het heeft DataMemberAttribute geen kenmerk om een cyclus te voorkomen.
// 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
De entiteiten serialiseren
U kunt de entiteiten als volgt serialiseren in de codes die in de vorige sectie worden weergegeven.
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()
Zelf recursieve relaties
Self-recursieve relaties volgen hetzelfde patroon. De koppelingseigenschap die overeenkomt met de refererende sleutel heeft DataMemberAttribute geen kenmerk, terwijl de bovenliggende eigenschap dat wel doet.
Houd rekening met de volgende klasse met twee zelf-recursieve relaties: Employee.Manager/Reports en 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)