SqlServer sin dalla versione 7.0 (non sono sicuro ancora pensavo ad altro smile_teeth ) supporta il retrieving dei dati sotto forma di xml grazie all'utilizzo di particolari parametri quali "FOR XML [RAW | AUTO [ELEMENTS] | EXPLICIT]". Un tipico codice di accesso ai dati che utilizzi una query FOR XML potrebbe avere una forma del tipo :

   1: string queryForXml ="SELECT Customers.ContactName FROM Customers FOR XML AUTO, ELEMENTS";
   2:             string connectionString = ConfigurationManager.AppSettings["ConnectionString"];
   3:             SqlConnection sqlconnection = new SqlConnection(connectionString);
   4:             try
   5:             {
   6:                 sqlconnection.Open();
   7:             }
   8:             catch { throw new Exception(connectionString); }
   9:             if (sqlconnection.State != ConnectionState.Open)
  10:                 throw new Exception("Connection unavailable");
  11:                 
  12:             SqlCommand cmd = new SqlCommand();
  13:             cmd.CommandText = queryForXml;
  14:             cmd.Connection = sqlconnection;
  15:             cmd.CommandType = CommandType.Text;
  16:             XmlReader xmlRead = cmd.ExecuteXmlReader();
  17:             sqlconnection.Close();

 L' XmlReader che ci viene restituito dal metodo ExecuteXmlReader della SqlCommand non può essere convertito direttamente in un XmlDocument per il semplice fatto che l 'XML restituito da SqlServer è composto da un insieme di Xml Fragment. In rete le uniche soluzioni che ho trovato si basano sull' utilizzo di StringReader, con un calo evidente delle performance, oppure tramite la creazione di un XPathDocument con annesso XPathNavigator;  la soluzione che ho elaborato è quella IMHO più elementare e al tempo stesso efficace: il workaround consiste nello sfruttare un overload del metodo Create della classe XmlReader utilizzando la classe XmlReaderSettings combinata alla classe XmlParserContext

 

   1: XmlReader textReader = null;
   2:                     XmlReaderSettings settings = new XmlReaderSettings();
   3:                     settings.ConformanceLevel = ConformanceLevel.Fragment;
   4:                     XmlParserContext context = new XmlParserContext(null, null, null, XmlSpace.None,
   5:                                                                      Encoding.Unicode);
   6:                     textReader = XmlReader.Create(mem, settings,context);

 

Il metodo ExecuteXmlReader dovrà quindi sfruttare al proprio interno un XmlReader come sopra definito in modo tale da essere a conoscenza che i dati da leggere sono frammenti XML e non XmlDocument well formed. Il codice che permette quindi di costruirsi un XmlDocument da un Xmlreader sarà del tipo:    

   1: XmlReader reader = cmd.CustomExecuteXmlReader();
   2:             XmlDocument document = new XmlDocument();
   3:             XmlNode root = document.CreateNode(XmlNodeType.Element, 
   4:                                                ConfigurationManager.AppSettings["rootNode"], null);
   5:             document.AppendChild(root);
   6:  
   7:             XmlNode nodo=null;
   8:             while ((nodo = document.ReadNode(reader)) != null)
   9:             {
  10:                 document.DocumentElement.AppendChild(nodo);
  11:             }

SqlServer 2005 ha ovviato a questo "problema" fornendo nelle query FOR XML la direttiva ROOT ma sono sicuro che ancora a lungo sarà molto diffuso l'utilizzo di SqlServer 2000. Ricordo che è possibile usare SQLXML con relativa SqlXmlCommand anche se una soluzione fatta in casa sarà sempre migliore

Ad maiora.....

Technorati tags: ,