Utilizar anotaciones con un DataSet con información de tipos
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 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 muchos escenarios, 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 Customer para typedName, el nombre de un objeto DataRow será Customer. Si se especifica el valor Customers para typedPlural se conservará el nombre Customers para DataRowCollection.
En la siguiente tabla se muestran las anotaciones disponibles.
Anotación | Description |
---|---|
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.
nullValue | Description |
---|---|
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 | Inicia una excepción. Éste 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 primario | TableNameRow | typedParent |
Eventos de 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).
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, incluyendo 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: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>
En el siguiente ejemplo de código se utiliza un DataSet con establecimiento inflexible de tipos creado a partir del esquema de ejemplo. Utiliza un DataAdapter para llenar la tabla Customers y otro DataAdapter para llenar la tabla Orders. El DataSet con establecimiento inflexible de tipos define las 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)
{
}
Vea también
Trabajar con DataSet con información de tipos | Crear y utilizar DataSets | DataColumnCollection (Clase) | DataSet (Clase)