Comentar conjuntos de datos con tipo
Las anotaciones permiten modificar los nombres de los elementos del DataSet con información de tipos sin modificar el esquema subyacente. La modificación de los nombres de los elementos del esquema subyacente haría que el DataSet con información de tipos hiciera referencia a objetos que no existen en el origen de datos, además de perder una referencia a los objetos existentes en el origen de datos.
Con las anotaciones es posible personalizar los nombres de objetos del DataSet con información de tipos para utilizar nombres más significativos; esto hace que el código sea más legible y que los clientes puedan utilizar más fácilmente el DataSet al tiempo que se deja intacto el esquema subyacente. Por ejemplo, el siguiente elemento de esquema para la tabla Customers de la base de datos Northwind da como resultado un nombre de objeto DataRow de CustomersRow y una DataRowCollection denominada Customers.
<xs:element name="Customers">
<xs:complexType>
<xs:sequence>
<xs:element name="CustomerID" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
Un nombre Customers para una DataRowCollection es significativo en el código de cliente, pero una DataRow denominada CustomersRow puede llevar a confusión porque se trata de un único objeto. Además, en situaciones normales, se haría referencia al objeto sin el identificador Row y en su lugar se haría referencia al mismo simplemente como un objeto Customer. La solución consiste en anotar el esquema e identificar nuevos nombres para los objetos DataRow y DataRowCollection. A continuación se muestra la versión anotada del esquema anterior.
<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>
Al especificar un valor de Customer para typedName, el nombre de un objeto DataRow será Customer. Si se especifica el valor de Customers para typedPlural se conservará el nombre Customers para DataRowCollection.
En la siguiente tabla se muestran las anotaciones disponibles.
Anotación | Descripción |
---|---|
typedName | Nombre del objeto. |
typedPlural | Nombre de una colección de objetos. |
typedParent | Nombre del objeto cuando se hace referencia al mismo en una relación primaria. |
typedChildren | Nombre del método para devolver objetos de una relación secundaria. |
nullValue | Valor si el valor subyacente es DBNull. Vea las anotaciones nullValue en la tabla siguiente. El valor predeterminado es _throw. |
En la tabla siguiente se presentan los valores que se pueden especificar para la anotación nullValue.
Valor nullValue | Descripción |
---|---|
Valor de reemplazo | Especifica un valor que se va a devolver. El valor devuelto debe coincidir con el tipo del elemento. Por ejemplo, utilice nullValue="0" para devolver 0 en el caso de campos null integer. |
_throw | Iniciar una excepción. Este es el valor predeterminado. |
_null | Devuelve una referencia nula o inicia una excepción si se encuentra un tipo primitivo. |
_empty | En el caso de cadenas, devuelve String.Empty; de lo contrario, devuelve un objeto creado desde un constructor vacío. Si se encuentra un tipo primitivo, inicia una excepción. |
En la siguiente tabla se muestran los valores predeterminados de los objetos en un DataSet con información de tipos y las anotaciones disponibles.
Objeto/Método/Evento | Valor predeterminado | Anotación |
---|---|---|
DataTable | TableNameDataTable | typedPlural |
Métodos de DataTable | NewTableNameRow AddTableNameRow DeleteTableNameRow |
typedName |
DataRowCollection | TableName | typedPlural |
DataRow | TableNameRow | typedName |
DataColumn | DataTable.ColumnNameColumn DataRow.ColumnName |
typedName |
Propiedad | PropertyName | typedName |
Descriptor de acceso secundario | GetChildTableNameRows | typedChildren |
Descriptor de acceso Parent | TableNameRow | typedParent |
Eventos DataSet | TableNameRowChangeEvent TableNameRowChangeEventHandler |
typedName |
Para utilizar anotaciones de DataSet con información de tipos debe incluir la siguiente referencia xmlns en el esquema del lenguaje de definición de esquemas XML (XSD). Para crear un xsd a partir de las tablas de base de datos, vea WriteXmlSchema o Trabajar con los conjuntos de datos en Visual Studio.
xmlns:codegen="urn:schemas-microsoft-com:xml-msprop"
A continuación se muestra un ejemplo de esquema anotado que expone la tabla Customers de la base de datos Northwind, incluida una relación con la tabla Orders.
<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="CustomerDataSet"
xmlns:codegen="urn:schemas-microsoft-com:xml-msprop"
xmlns=""
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>
En el siguiente ejemplo de código se utiliza un DataSet con tipo fuerte creado a partir del esquema de ejemplo. Utiliza un SqlDataAdapter para rellenar la tabla Customers y otro SqlDataAdapter para rellenar la tabla Orders. El DataSet con tipo fuerte define las 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.NewCustomer()
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.NewCustomer();
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)
{
}