Inserimento di annotazioni in DataSet tipizzati (ADO.NET)
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, 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 della raccolta 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.
Valore nullValue |
Descrizione |
---|---|
Valore di sostituzione |
Specifica 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. Questo è il valore predefinito. |
_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 oggetto 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 Child |
GetChildTableNameRows |
typedChildren |
Funzione di accesso Parent |
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="OrderAdapter"
codegen:typedName="OrderAdapter"
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 fortemente tipizzato creato dallo schema di esempio. Un SqlDataAdapter viene utilizzato per compilare la tabella Customers e un altro SqlDataAdapter per compilare la tabella Orders. Il DataSet fortemente tipizzato definisce l'oggetto DataRelations.
' Assumes a valid SqlConnection object named connection.
Dim customerAdapter As SqlDataAdapter = New SqlDataAdapter( _
"SELECT CustomerID, CompanyName, Phone FROM Customers", &
connection)
Dim orderAdapter As SqlDataAdapter = New SqlDataAdapter( _
"SELECT OrderID, CustomerID, EmployeeID, OrderAdapter FROM Orders", &
connection)
' Populate a strongly typed DataSet.
connection.Open()
Dim customers As CustomerDataSet = New CustomerDataSet()
customerAdapter.Fill(customers, "Customers")
orderAdapter.Fill(customers, "Orders")
connection.Close()
' Add a strongly typed event.
AddHandler customers.Customers.CustomerChanged, &
New CustomerDataSet.CustomerChangeEventHandler( _
AddressOf OnCustomerChanged)
' Add a strongly typed DataRow.
Dim newCustomer As CustomerDataSet.Customer = _
customers.Customers.NewCustomeromer()
newCustomer.CustomerID = "NEW01"
newCustomer.CompanyName = "My New Company"
customers.Customers.AddCustomer(newCustomer)
' Navigate the child relation.
Dim customer As CustomerDataSet.Customer
Dim order As CustomerDataSet.Order
For Each customer In customers.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
// Assumes a valid SqlConnection object named connection.
SqlDataAdapter customerAdapter = new SqlDataAdapter(
"SELECT CustomerID, CompanyName, Phone FROM Customers",
connection);
SqlDataAdapter orderAdapter = new SqlDataAdapter(
"SELECT OrderID, CustomerID, EmployeeID, OrderAdapter FROM Orders",
connection);
// Populate a strongly typed DataSet.
connection.Open();
CustomerDataSet customers = new CustomerDataSet();
customerAdapter.Fill(customers, "Customers");
orderAdapter.Fill(customers, "Orders");
connection.Close();
// Add a strongly typed event.
customers.Customers.CustomerChanged += new
CustomerDataSet.CustomerChangeEventHandler(OnCustomerChanged);
// Add a strongly typed DataRow.
CustomerDataSet.Customer newCustomer =
customers.Customers.NewCustomeromer();
newCustomer.CustomerID = "NEW01";
newCustomer.CompanyName = "My New Company";
customers.Customers.AddCustomer(newCustomer);
// Navigate the child relation.
foreach(CustomerDataSet.Customer customer in customers.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)
{
}