Compatibilidad con tipos de datos XML en ADO.NET 2.0: trabajo con XML desde SQL Server 2005
TOC
Collapse the table of content
Expand the table of content

Compatibilidad con tipos de datos XML en ADO.NET 2.0: trabajo con XML desde SQL Server 2005

18 de Julio de 2005

Publicado: Octubre de 2004

Bob Beauchemin

Este artículo se aplica a:


Resumen: vea cómo se aúnan las mejoras a la compatibilidad con XML en Microsoft ADO.NET 2.0 y Microsoft SQL Server 2005 para facilitar el manejo de datos XML en sus aplicaciones. (13 páginas impresas.) (Este artículo contiene vínculos a páginas en inglés.)

En esta página

Introducción Introducción
¿XML o una cadena? ¿XML o una cadena?
Documentos, fragmentos y compatibilidad con FOR XML Documentos, fragmentos y compatibilidad con FOR XML
Uso de la compatibilidad con el esquema XML en el cliente Uso de la compatibilidad con el esquema XML en el cliente
Conclusión Conclusión

Introducción

Uno de los cambios fundamentales de Microsoft SQL Server 2005 es la inclusión del tipo de datos XML. Este tipo de datos es un tipo de primera clase, al igual que INT o VARCHAR; SQL Server 2005 permite realizar consultas en contexto de este tipo de datos mediante una serie de funciones específicas de XML. También se admite el almacenamiento de colecciones de esquemas XML en la base de datos, lo que habilita la validación de esquemas basada en bases de datos. Además, SQL Server 2005 amplía en gran medida la funcionalidad de composición de XML (los dialectos SELECT ... FOR XML) y la función de descomposición XML OpenXML(). Además, proporciona una nueva función nodes() con el tipo de datos XML para realizar una descomposición más ligera.

Con todas estas novedades y mejoras en la funcionalidad XML del servidor de la base de datos, no es ninguna sorpresa que también se haya mejorado el proveedor de datos SqlClient de Microsoft ADO.NET 2.0. Asimismo existen cambios en DataSet de ADO.NET, que ahora admite un DataColumn de tipo XML, y además se han ampliado los "puntos de integración" entre System.Data y System.Xml. En este artículo veremos el uso del tipo de datos XML de SQL Server 2005 en el cliente.

Hay dos tipos de resultados XML que SQL Server 2005 puede generar. La instrucción SELECT * FROM AUTHORS FOR XML AUTO genera una secuencia XML y no un conjunto de filas con una columna y una fila. Este tipo de resultado no ha cambiado desde SQL Server 2000. El resultado de secuencia XML aparece en el Analizador de consultas SQL Server como un conjunto de filas con una columna y una fila, debido a las limitaciones de la herramienta Analizador de consultas. Puede diferenciar esta secuencia respecto a una columna "normal" mediante su nombre de identificador único especial "XML_F52E2B61-18A1-11d1-B105-000805F49916B". Este nombre es en realidad un indicador del analizador subyacente de TDS (secuencia de datos tabular, el formato de red de SQL Server) de que la columna se debe transmitir mediante secuencias al cliente, en vez de enviarla como si fuera un conjunto de filas habitual. Existe un método especial, SqlCommand.ExecuteXmlReader, que permite recuperar esta secuencia en el cliente. En SQL Server 2005, el dialecto SELECT ... FOR XML se ha mejorado de varias maneras. Entre ellas se incluyen:

  1. Hay un nuevo modo FOR XML PATH de fácil manejo que se puede emplear en la mayoría de los casos en los que es necesario el modo FOR XML EXPLICIT en SQL Server 2000.

  2. Es posible generar una columna de tipo de datos XML además de la secuencia mediante una directiva TYPE.

  3. Se pueden anidar expresiones FOR XML.

  4. SELECT ... FOR XML puede generar documentos XML, así como fragmentos XML mediante una directiva ROOT.

  5. Es posible adjuntar un esquema XSD estándar al final de la secuencia.

La primera indicación de que XML es ahora un tipo de base de datos relacional de primera clase se percibe al hacer referencia a las enumeraciones relacionales datatype de ADO.NET 2.0. System.Data.DbType y System.Data.SqlDbType contienen valores adicionales para DbType.Xml y SqlDbType.Xml, respectivamente. También hay una nueva clase en el espacio de nombres System.Data.SqlTypes, SqlXml. Esta clase funciona como un generador de instancias XmlReader en la parte superior del valor de tipo XML. Se analizará el siguiente fragmento de código. Supongamos que tenemos una tabla de SQL Server con el siguiente aspecto:

CREATE TABLE xmltab (
  id INT IDENTITY PRIMARY KEY,
  xmlcol XML)

Puedo consultar esta tabla en el cliente mediante el siguiente código de ADO.NET 2.0.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Xml;

void GetXMLColumn {
// "Generic Coding..." article for shows how to
// get a connection string from a config file
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd = new SqlCommand(
       "select * from xmltab", conn))
 {
  conn.Open();
  SqlDataReader rdr = cmd.ExecuteReader();
  DataTable t = rdr.GetSchemaTable();

  while (rdr.Read())
    {
      SqlXml sx = rdr.GetSqlXml(1);
      XmlReader xr = sx.CreateReader();
      xr.Read(); 
      Console.WriteLine(xr.ReadOuterXml());
    }
 }
}

Los metadatos de columna que se devuelven al examinar el DataTable generado por GetSchemaTable identifican correctamente la columna:

ProviderType: 25 (25 = XML)
ProviderSpecificDataType: System.Data.SqlTypes.SqlXml
DataType: System.Xml.XmlReader
DataTypeName:

Presenta el mismo aspecto que cualquier otro tipo incorporado en SQL Server. Observe que el "tipo .NET" de esta columna es XmlReader y para .NET es como cualquier otro XML que se haya cargado de un archivo o se haya generado con la clase XmlDocument. El uso de la columna de tipo de datos XML como parámetro en un procedimiento almacenado o como una instrucción parametrizada en ADO.NET 2.0 es igualmente directo:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Xml;

void AddARow {
// get a connection string from a config file
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd = new SqlCommand(
       "insert xmltab(xmlcol) VALUES(@x)", conn))
 {
  conn.Open();
  cmd.Parameters.Add("@x", SqlDbType.Xml);

  // connect the parameter value to a file
  XmlReader xr = XmlReader.Create("somexml.xml");
  cmd.Parameters[0].Value = new SqlXml(xr);
  int i = cmd.ExecuteNonQuery();
 }
}

¿XML o una cadena?

Los dos métodos del código anterior utilizan el tipo de datos específico de SQL Server en SqlTypes. Si se utiliza el método de descriptor de acceso más genérico SqlReader, GetValue(), el valor es bastante diferente. La columna no aparece como un XmlReader sino como una clase String de .NET. Observe que, incluso aunque los metadatos identifiquen el tipo de datos de .NET de la columna como XmlReader, no es posible enviar la columna a un XmlReader. El uso de cualquier descriptor de acceso que no sea GetSqlXml() devolverá una cadena.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Xml;

void GetXMLColumn {
// get a connection string from a config file
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd = new SqlCommand(
       "select * from xmltab", conn))
 {
  conn.Open();
  SqlDataReader rdr = cmd.ExecuteReader();
  // prints "System.String"
  Console.WriteLine(rdr[1].GetType()); 
  
  // fails, invalid cast
  XmlReader xr = (XmlReader)rdr[1];

  // this works
  string s = (string)rdr[1];
 }
}

Incluso aunque se utilice el método SqlReader.GetProviderSpecificValue() se devuelve una cadena. En cierto modo, esto resulta algo extraño ya que GetProviderSpecificFieldType devuelve correctamente System.Sql.Types.SqlXml. Parece que podría ser un problema de la versión beta actual del proveedor, por lo que me abstendré de utilizar este método por ahora.

// System.Data.SqlTypes.SqlXml
Console.WriteLine(rdr.GetProviderSpecificFieldType(1));

// System.Data.SqlTypes.SqlString
Object o = rdr.GetProviderSpecificValue(1);
Console.WriteLine(o.GetType());

SqlClient proporciona una funcionalidad simétrica para los parámetros XML; también se puede utilizar el tipo de datos String. La posibilidad de pasar una cadena (NVARCHAR) en la que se espera un tipo XML depende de que SQL Server proporcione una conversión automática de VARCHAR o NVARCHAR en el tipo de datos XML. Observe que esta conversión también se puede realizar en el cliente, como se muestra en el siguiente ejemplo. Para ello, podemos proporcionar al procedimiento almacenado insert_xml una manera de realizar una conversión automática de string/NVARCHAR a XML.

-- T-SQL stored procedure definition
CREATE PROCEDURE insert_xml(@x XML)
AS
INSERT xmltab(xmlcol) VALUE(@x)

// client-side code
using System;
using System.Data;
using System.Data.SqlClient;

void InsertXMLFromClient {
// get a connection string from a config file
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd1 = new SqlCommand(
       "INSERT xmltab(xmlcol) VALUES(@x)", conn))
using (SqlCommand cmd2 = new SqlCommand(
       " insert_xml", conn))
 {
  string str = "<somedoc/>";

  conn.Open();
  
  // server-side conversion
  cmd1.Parameters.Add("@x", SqlDbType.NVarChar);
  cmd1.Parameters[0].Value = str;
  cmd1.ExecuteNonQuery();

  // client-side conversion works too
  cmd2.CommandType = CommandType.StoredProcedure;
  cmd2.Parameters.Add("@x", SqlDbType.Xml);
  cmd2.Parameters[0].Value = s;
  cmd2.ExecuteNonQuery();
 }
}

Documentos, fragmentos y compatibilidad con FOR XML

El tipo de datos XML de SQL Server 2005 admite tanto documentos XML como fragmentos de documentos XML. Un fragmento se diferencia de un documento en que los fragmentos pueden contener varios elementos de nivel superior y nodos de texto vacíos. Con columnas, variables o parámetros de tipo XML, es posible especificar si se permitirán fragmentos mediante la especificación DOCUMENT (no se permiten fragmentos) o CONTENT (se permiten fragmentos). El valor predeterminado es CONTENT y XML sin tipo admite los fragmentos. Este código T-SQL muestra la compatibilidad con los fragmentos:

CREATE TABLE xmltab (
  id INT IDENTITY PRIMARY KEY,
  xmlcol XML)
GO

-- insert a document
INSERT xmltab VALUES('<doc/>')
-- fragment, multiple top-level elements
INSERT xmltab VALUES('<doc/><doc/>')
-- fragment, bare text node
INSERT xmltab VALUES('Hello World')
-- even this fragment works
INSERT xmltab VALUES('<doc/>sometext')

Los fragmentos XML también se generan mediante SELECT ... FOR XML. La instrucción SELECT job_id, min_lvl, max_lvl FROM jobs FOR XML AUTO genera el siguiente resultado. Observe que hay varios elementos raíz.

<jobs job_id="1" min_lvl="10" max_lvl="10" />
<jobs job_id="2" min_lvl="200" max_lvl="250" />
<jobs job_id="3" min_lvl="175" max_lvl="225" />
<jobs job_id="4" min_lvl="175" max_lvl="250" />
<!-- some jobs rows deleted for compactness -->

Los documentos y los fragmentos se admiten mediante SqlXml. El método CreateReader() de SqlXml crea siempre un XmlReader que admite fragmentos mediante la nueva clase XmlReaderSettings de esta manera:

// pseudocode from SqlXml.CreateReader
    Stream stm = stm; // stream filled from column (code elided)
    XmlReaderSettings settings = new XmlReaderSettings();
    settings.ConformanceLevel = ConformanceLevel.Fragment;
    XmlReader xr = XmlReader.Create(
       stm, String.Empty, null, null,settings);

Puede utilizar fragmentos XML en parámetros de entrada si crea el XmlReader de la misma manera. Aunque la compatibilidad con fragmentos se incorpora al crear el tipo SqlXml, es preciso tener cuidado con el manejo de un XmlReader que contenga fragmentos. Tenga en cuenta que al llamar a XmlReader.GetOuterXml() sólo se proporcionará el primer fragmento; para colocar el XmlReader para obtener los fragmentos siguientes, es necesario volver a llamar al método Read de XmlReader. Lo veremos más adelante en este mismo artículo.

El "SELECT ... FOR XML" de T-SQL generaba una secuencia XML en vez de un conjunto de filas de una columna y una fila. También proporcionaba XML en un formato binario en vez de la serialización estándar de XML. Debido a las diferencias de formato y también a que "SELECT ... FOR XML" siempre producía fragmentos, era necesario un método especial para consumirlo. SqlClient implementa un método específico del proveedor, SqlCommand.ExecuteXmlReader, con este fin. Con SQL Server 2000 y ADO 1.0/1.1, es necesario utilizar ExecuteXmlReader para obtener los resultados de una consulta FOR XML, a menos que se desee utilizar algún subterfugio que requiera la concatenación de cadenas. Con las mejoras del FOR XML de SQL Server 2005 y la compatibilidad con XML como tipo de datos, basta con utilizar ExecuteXmlReader para obtener una única secuencia XML de SQL Server. Como todo el código escrito para SQL Server 2000 lo utilizaba, este método se admite y se ha mejorado en ADO.NET 2.0.

Puede utilizar ExecuteXmlReader para recuperar cualquier secuencia de una consulta "FOR XML", al igual que en las versiones anteriores. Además, este método admite la recuperación de una columna de tipo de datos XML generada por una instrucción SELECT. La única advertencia que hay que tener en cuenta es que cuando una instrucción SELECT devuelve más de una fila, ExecuteXmlReader devuelve únicamente el contenido de la primera fila. A continuación, vemos un ejemplo que ilustra esto utilizando la misma tabla de los ejemplos anteriores:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Xml;

void UseExecXmlReader {
// get a connection string from a config file
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd1 = new SqlCommand(
       "select * from pubs..authors for xml auto,root('root')", conn))
using (SqlCommand cmd2 = new SqlCommand(
       "select * from pubs..authors for xml auto", conn))
using (SqlCommand cmd3 = new SqlCommand(
       "select * from xmltab", conn))
 {
  conn.Open();
  // contains document
  XmlReader xr1 = cmd1.ExecuteXmlReader();
  // contains fragment
  XmlReader xr2 = cmd2.ExecuteXmlReader();
  // contains contents of first row in xmltab only
  XmlReader xr3 = cmd3.ExecuteXmlReader();
  // use XmlReaders, then
  xr1.Dispose(); xr2.Dispose(); xr3.Dispose();
 }
}

Para finalizar el estudio de la obtención de XML en ADO.NET 2.0 resulta útil mencionar el período de vida del contenido XmlReader en varios escenarios de uso. El conocimiento del período de vida de XmlReader también ayuda a comprender el almacenamiento realizado por SqlClient y cómo utilizar estos datos para lograr el máximo rendimiento. El XmlReader utiliza recursos y para liberarlos, es necesario llamar a los métodos Close() o Dispose(), al igual que con SqlConnection, SqlCommand y SqlDataReader. En caso de que estemos leyendo columnas XML mediante un SqlDataReader, puede haber un XmlReader asignado para cada fila. Recuerde que, para poder retroceder a través de columnas de la misma fila o moverse a la siguiente fila, es necesario almacenar en memoria el contenido de XmlReader. Al utilizar CommandBehavior.SequentialAccess de SqlCommand no se almacenará todo el XmlReader en la memoria, pero debe tener más cuidado al utilizar este método de acceso. El XmlReader asociado con una columna debe consumirse completamente antes de pasar a la siguiente columna del conjunto de filas si utiliza CommandBehavior.SequentialAccess; tras pasar a la siguiente columna, el XmlReader parece ser válido, pero al llamar a su método Read() no se obtienen datos. Al utilizar ExecuteXmlReader o ExecuteScalar en lugar de ExecuteReader, no es necesario tener muy en cuenta este comportamiento, pero no se olvide de aplicar Close o Dispose al XmlReader, en cualquier caso.

Uso de la compatibilidad con el esquema XML en el cliente

SQL Server 2005 admite XML con tipos seguros, lo que significa que XML debe cumplir un esquema XML o un conjunto de esquemas XML. Esta compatibilidad se habilita mediante el uso de las colecciones de esquemas XML de SQL Server. Las colecciones de esquemas XML se definen como cualquier otro objeto de SQL Server y los esquemas XML se almacenan en SQL Server. El uso de la instrucción DDL CREATE de T-SQL y la colección de esquemas XML presenta el siguiente aspecto:

CREATE XML SCHEMA COLLECTION books_xsd
AS
-- one or more XML schemas here
GO

CREATE TABLE typed_xml (
  id INT IDENTITY PRIMARY KEY,
  -- require books_col content to be schema-valid
  books_col XML(books_xsd)
)
-- validated here
INSERT typed_xml VALUES('<!-- some document -->')
-- validated here too
UPDATE typed_xml
  SET books_col.modify('<!-- some XQuery DML -->')
  WHERE id = 1

Al utilizar datos XML de tipo seguro dentro de SQL Server 2005 desde el cliente, la validación se realiza en el servidor y no en el cliente. Como ejemplo, si se utiliza el método AddARow mostrado en el ejemplo anterior para agregar una fila a la tabla typed_xml, los datos se envían a través de la red a SQL Server antes de que se produzca la validación. No obstante, con un poco de esfuerzo es posible recuperar los esquemas XML de la colección de esquemas XML de SQL Server y colocarlos en el cliente para lograr una validación en el cliente. De esta forma, es posible ahorrarse algunos recorridos de ida y vuelta, al evitar que un usuario o un servicio Web puedan enviar XML que no cumpla el esquema al cliente para su almacenamiento en SQL Server. No obstante, hay que tener en cuenta dos aclaraciones y advertencias. En primer lugar, confiar en la información sobre el esquema XML obtenida de SQL Server es como confiar en otros metadatos almacenados en la memoria caché del cliente. Existe la posibilidad de que alguien haya modificado la colección de esquemas mediante la instrucción ALTER XML SCHEMA de T-SQL o incluso haya borrado la colección de esquemas y la haya vuelto a crear, por lo que no serviría de nada la comprobación realizada en el cliente. Puede evitar llevarse sorpresas si utiliza una notificación de evento en las instrucciones CREATE/ALTER/DROP XML SCHEMA DDL. A continuación, tendría que utilizar código personalizado para supervisar el servicio Service Broker de manera similar a cuando se utiliza SqlNotificationRequest con notificaciones de consulta. Las notificaciones de evento son una de las novedades de SQL Server 2005, aunque son similares a las notificaciones de consulta tratadas en mi artículo anterior, Query Notifications in ADO.NET 2.0. En segundo lugar, tenga en cuenta que aunque se realice la validación según el esquema XML en el cliente, SQL Server repetirá la comprobación en el servidor. No hay manera de indicarle a SQL Server: "Sé que esta instancia de XML con tipo de esquema de SQL Server es válida según el esquema, por lo que no te molestes en comprobarlo".

Para realizar la validación según el esquema XML en el cliente, puede recuperar la colección de esquemas XML de SQL Server mediante la función xml_schema_namespace() de T-SQL. Para ello, es necesario un nombre de colección de esquemas XML y un nombre de esquema de base de datos, ya que las colecciones de esquemas XML tienen ámbitos de esquemas de bases de datos. Podemos incluirlos en código en el programa o extraerlos de los metadatos del conjunto de filas en el cliente. Ya se utilice el método anterior GetSchemaTable de SqlDataReader o la nueva clase SqlMetaData, es fácil obtener el nombre de la colección de esquemas asociada con una determinada columna. A continuación, vemos un breve ejemplo:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.Sql;

void GetCollectionInfo {
// get a connection string from a config file
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd = new SqlCommand(
       "select books_col from typed_xml", conn))
{
  conn.Open();
  // fetch only SQL Server metadata
  SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.SchemaOnly);

  SqlMetaData md = rdr.GetSqlMetaData(0);
  string database = md.XmlSchemaCollectionDatabase;
  string schema = md.XmlSchemaCollectionOwningSchema;
  string collection = md.XmlSchemaCollectionName;
}
}

Una vez que hemos determinado la colección del esquema XML que hay que recuperar, puede utilizar la función T-SQL para recuperarla en un XmlSchemaSet en el cliente. Observe que este ejemplo también muestra cómo recuperar un fragmento mediante un XmlReader, lo cual es necesario ya que podría haber más de un esquema XML en una colección de esquemas XML; la función xml_schema_namespace devolverá todos los esquemas XML de la colección como un fragmento.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Xml;
using System.Xml.Schema;

void GetSchemaSet {
// get a connection string from a config file
string s = GetConnectStringFromConfigFile("xmldb");
using (SqlConnection conn = new SqlConnection(s))
using (SqlCommand cmd = new SqlCommand(
       "SELECT xml_schema_namespace(N'dbo',N'books_xsd')", conn))
 {
  XmlSchemaSet ss = new XmlSchemaSet();
  conn.Open();
  SqlDataReader rdr = cmd.ExecuteReader();
  rdr.Read();
  XmlReader xr = rdr.GetSqlXml(0).CreateReader();

  do
  {
    ss.Add(XmlSchema.Read(xr, null));
    xr.Read();
  }
  while (xr.NodeType == XmlNodeType.Element);
 }
}

Con XmlSchemaSet se puede integrar el código de validación XML en el cliente en nuestra rutina Add y se obtendrá la validación en el cliente.

void ValidateAndStore(XmlSchemaSet ss)
{
  // associate the XmlSchemaSet with the XmlReader
  XmlReaderSettings settings = new XmlReaderSettings();
  settings.Schemas = ss;
  string s = GetConnectStringFromConfigFile("xmldb");
  using (XmlReader xr = XmlReader.Create(
    "file://c:/temp/somefile.xml", settings))
  // get a connection string from a config file
  using (SqlConnection conn = new SqlConnection(s))
  using (SqlCommand cmd = new SqlCommand(
    "insert typed_xml values(@x)", conn))
  {
    try
    {
      conn.Open();
      // should throw an exception here if not schema valid
      cmd.Parameters.AddWithValue("@x", new SqlXml(xr));
      int i = cmd.ExecuteNonQuery();
    }
    catch (Exception e)
    {
       Console.WriteLine(e.Message);
    }
  }
}

Aunque la validación según el esquema XML en el cliente no es algo que todas las aplicaciones exijan, es bueno saber que está disponible si la aplicación lo necesita. También se generan esquemas XML cuando se utiliza la nueva opción XMLSCHEMA de SQL Server 2005 en SELECT...FOR XML de esta manera:

SELECT * FROM authors FOR XML AUTO, ELEMENTS, XMLSCHEMA

También puede dividir el fragmento y recuperar el XmlSchemaSet en el cliente para estos tipos de consultas, aunque hay ciertas limitaciones a la hora de llevar esto a la práctica en la versión beta actual.

Conclusión

Hemos visto cómo utilizar el nuevo tipo XML y las nuevas características de FOR XML para consumir XML de Microsoft SQL Server en el SqlClient de Microsoft ADO.NET y también cómo utilizar SqlClient para insertar XML en las tablas de SQL Server. En realidad, hay cierta funcionalidad XML mejorada en el DataSet que no he mencionado; más adelante aparecerá una serie de artículos sobre las mejoras del DataSet de ADO 2.0. Puede obtener más información acerca del uso de los datos XML de SQL Server en el artículo en línea de MSDN XML Support in Microsoft SQL Server 2005 de Shankar Pal, Mark Fussell e Irwin Dolobowsky; más información sobre las mejoras de SELECT...FOR XML en el artículo en línea de MSDN What's New in FOR XML in Microsoft SQL Server 2005 de Michael Rys; para obtener más información acerca de System.Xml en .NET 2.0, consulte What's New in System.Xml for Visual Studio 2005 and the .NET Framework 2.0 Release de Mark Fussell. Podemos decir con seguridad que XML se ha integrado con ADO.NET 2.0 y SqlClient a muchos niveles, siendo la integración de los modelos de datos la más estrecha jamás realizada.

Acerca del autor

Mostrar:
© 2016 Microsoft