Utilizzo delle annotazioni con un DataSet tipizzato
Le annotazioni consentono di modificare i nomi degli elementi nel DataSet tipizzato, senza modificare lo schema sottostante. Se si modificassero i nomi degli elementi dello schema sottostante, i riferimenti presenti nel DataSet punterebbero a oggetti non più esistenti nell'origine dati e si perderebbe un riferimento agli oggetti esistenti nell'origine dati.
L'utilizzo delle annotazioni consente di personalizzare i nomi degli oggetti presenti nel DataSet tipizzato assegnando nomi più significativi, in modo da migliorare la leggibilità del codice e facilitare l'utilizzo del DataSet da parte dei client, pur mantenendo intatto lo schema sottostante. Dal seguente elemento di schema per la tabella Customers del database Northwind ad esempio si ottiene come risultato un nome oggetto DataRow corrispondente a CustomersRow e un oggetto DataRowCollection denominato Customers.
<xs:element name="Customers">
<xs:complexType>
<xs:sequence>
<xs:element name="CustomerID" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
Il nome Customers per un oggetto DataRowCollection risulta significativo nel codice del client, mentre il nome CustomersRow per DataRow potrebbe generare confusione, poiché si tratta di un unico oggetto. Negli scenari più comuni inoltre ci si riferisce all'oggetto senza specificare l'identificatore Row e indicando tale oggetto nel riferimento semplicemente come oggetto Customer. La soluzione consiste nell'inserire annotazioni nello schema e nell'identificare nuovi nomi per gli oggetti DataRow e DataRowCollection. Di seguito viene riportata una versione annotata dello schema precedente.
<xs:element name="Customers" codegen:typedName="Customer" codegen:typedPlural="Customers">
<xs:complexType>
<xs:sequence>
<xs:element name="CustomerID" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
Se si specifica un valore typedName pari a Customer, si otterrà un nome per l'oggetto DataRow corrispondente a Customer. Specificando un valore typedPlural pari a Customers, si conserva il nome Customers per DataRowCollection.
Nella seguente tabella sono indicate le annotazioni disponibili.
Annotazione | Descrizione |
---|---|
typedName | Nome dell'oggetto. |
typedPlural | Nome dell'insieme di oggetti. |
typedParent | Nome dell'oggetto quando si fa riferimento a tale oggetto in una relazione padre. |
typedChildren | Nome del metodo per la restituzione di oggetti da una relazione figlio. |
nullValue | Valore specificato se il valore sottostante è DBNull. Per le annotazioni di tipo nullValue, vedere la tabella seguente. Il valore predefinito è _throw. |
Nella tabella seguente vengono elencati i valori che è possibile utilizzare per le annotazioni di tipo nullValue.
nullValue | Descrizione |
---|---|
Valore di sostituzione | Consente di specificare il valore da restituire. È necessario che il valore restituito corrisponda al tipo dell'elemento. Utilizzare ad esempio nullValue="0" per restituire 0 per i campi integer null. |
_throw | Generazione di un'eccezione. Si tratta dell'impostazione predefinita. |
_null | Consente di restituire un riferimento null o di generare un'eccezione se viene rilevato un tipo primitivo. |
_empty | Nel caso delle stringhe consente di restituire String.Empty, negli altri casi consente di restituire un oggetto creato da un costruttore vuoto. Se viene rilevato un tipo primitivo, consente di generare un'eccezione. |
Nella tabella seguente vengono elencati i valori predefiniti per gli oggetti di un DataSet tipizzato e le annotazioni disponibili.
Oggetto/Metodo/Evento | Valore predefinito | Annotazione |
---|---|---|
DataTable | TableNameDataTable | typedPlural |
Metodi DataTable | NewTableNameRow
AddTableNameRow DeleteTableNameRow |
typedName |
DataRowCollection | TableName | typedPlural |
DataRow | TableNameRow | typedName |
DataColumn | DataTable.ColumnNameColumn
DataRow.ColumnName |
typedName |
Proprietà | PropertyName | typedName |
Funzione di accesso figlio | GetChildTableNameRows | typedChildren |
Funzione di accesso padre | TableNameRow | typedParent |
Eventi DataSet | TableNameRowChangeEvent
TableNameRowChangeEventHandler |
typedName |
Per utilizzare le annotazioni del DataSet tipizzato, è necessario includere il seguente riferimento xmlns nello schema XSD (Schema Definition Language) di XML.
xmlns:codegen="urn:schemas-microsoft-com:xml-msprop"
Di seguito viene riportato un esempio di schema annotato in cui viene esposta la tabella Customers del database Northwind con inclusa una relazione alla tabella Orders.
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="CustomerDataSet"
xmlns:codegen="urn:schemas-microsoft-com:xml-msprop"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="CustomerDataSet" msdata:IsDataSet="true">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="Customers" codegen:typedName="Customer" codegen:typedPlural="Customers">
<xs:complexType>
<xs:sequence>
<xs:element name="CustomerID" codegen:typedName="CustomerID" type="xs:string" minOccurs="0" />
<xs:element name="CompanyName" codegen:typedName="CompanyName" type="xs:string" minOccurs="0" />
<xs:element name="Phone" codegen:typedName="Phone" codegen:nullValue="" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Orders" codegen:typedName="Order" codegen:typedPlural="Orders">
<xs:complexType>
<xs:sequence>
<xs:element name="OrderID" codegen:typedName="OrderID" type="xs:int" minOccurs="0" />
<xs:element name="CustomerID" codegen:typedName="CustomerID" codegen:nullValue="" type="xs:string" minOccurs="0" />
<xs:element name="EmployeeID" codegen:typedName="EmployeeID" codegen:nullValue="0" type="xs:int" minOccurs="0" />
<xs:element name="OrderDate" codegen:typedName="OrderDate" codegen:nullValue="1980-01-01T00:00:00" type="xs:dateTime" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
<xs:unique name="Constraint1">
<xs:selector xpath=".//Customers" />
<xs:field xpath="CustomerID" />
</xs:unique>
<xs:keyref name="CustOrders" refer="Constraint1" codegen:typedParent="Customer" codegen:typedChildren="GetOrders">
<xs:selector xpath=".//Orders" />
<xs:field xpath="CustomerID" />
</xs:keyref>
</xs:element>
</xs:schema>
Nell'esempio di codice seguente viene utilizzato un DataSet tipizzato in modo sicuro creato dallo schema di esempio. Un DataAdapter viene utilizzato per compilare la tabella Customers e un altro DataAdapter per compilare la tabella Orders. Il DataSet tipizzato in modo sicuro consente di definire l'oggetto DataRelations.
Dim nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;Integrated Security=SSPI;" & _
"Initial Catalog=northwind")
Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT CustomerID, CompanyName, Phone FROM Customers", &
nwindConn)
Dim orderDA As SqlDataAdapter = New SqlDataAdapter("SELECT OrderID, CustomerID, EmployeeID, OrderDate FROM Orders", &
nwindConn)
' Populate a strongly typed DataSet.
nwindConn.Open()
Dim custDS As CustomerDataSet = New CustomerDataSet()
custDA.Fill(custDS, "Customers")
orderDA.Fill(custDS, "Orders")
nwindConn.Close()
' Add a strongly typed event.
AddHandler custDS.Customers.CustomerChanged, &
New CustomerDataSet.CustomerChangeEventHandler(AddressOf OnCustomerChanged)
' Add a strongly typed DataRow.
Dim newCust As CustomerDataSet.Customer = custDS.Customers.NewCustomer()
newCust.CustomerID = "NEW01"
newCust.CompanyName = "My New Company"
custDS.Customers.AddCustomer(newCust)
' Navigate the child relation.
Dim customer As CustomerDataSet.Customer
Dim order As CustomerDataSet.Order
For Each customer In custDS.Customers
Console.WriteLine(customer.CustomerID)
For Each order In customer.GetOrders()
Console.WriteLine(vbTab & order.OrderID)
Next
Next
Private Shared Sub OnCustomerChanged(sender As Object, e As CustomerDataSet.CustomerChangeEvent)
End Sub
[C#]
SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");
SqlDataAdapter custDA = new SqlDataAdapter("SELECT CustomerID, CompanyName, Phone FROM Customers", nwindConn);
SqlDataAdapter orderDA = new SqlDataAdapter("SELECT OrderID, CustomerID, EmployeeID, OrderDate FROM Orders", nwindConn);
// Populate a strongly typed DataSet.
nwindConn.Open();
CustomerDataSet custDS = new CustomerDataSet();
custDA.Fill(custDS, "Customers");
orderDA.Fill(custDS, "Orders");
nwindConn.Close();
// Add a strongly typed event.
custDS.Customers.CustomerChanged += new
CustomerDataSet.CustomerChangeEventHandler(OnCustomerChanged);
// Add a strongly typed DataRow.
CustomerDataSet.Customer newCust = custDS.Customers.NewCustomer();
newCust.CustomerID = "NEW01";
newCust.CompanyName = "My New Company";
custDS.Customers.AddCustomer(newCust);
// Navigate the child relation.
foreach(CustomerDataSet.Customer customer in custDS.Customers)
{
Console.WriteLine(customer.CustomerID);
foreach(CustomerDataSet.Order order in customer.GetOrders())
Console.WriteLine("\t" + order.OrderID);
}
protected static void OnCustomerChanged(object sender, CustomerDataSet.CustomerChangeEvent e)
{
}
Vedere anche
Utilizzo di un DataSet tipizzato | Creazione e utilizzo di DataSet | Classe DataColumnCollection | Classe DataSet