2009-04-14 19 views
6

È necessario passare i parametri come Xml alle stored procedure.Passaggio dei parametri come Xml a una stored procedure

Ho un servizio WCF nel livello intermedio che effettua chiamate al mio livello dati che a sua volta inoltra la richiesta alla stored procedure appropriata.

Il progetto è che il servizio WCF è responsabile della creazione dell'XML da passare al repository.

Mi chiedo se mantenere il controllo di quali parametri sono contenuti nell'Xml nel livello intermedio o utilizzare un dizionario creato dal client che poi convertirò in Xml nel livello intermedio?

Al momento io sono andato per la seconda - per esempio:

public TestQueryResponseMessage TestQuery(TestQueryRequestMessage message) 
{ 
     var result = Repository.ExecuteQuery("TestQuery", ParamsToXml(message.Body.Params)); 

     return new TestQueryResponseMessage 
     { 
      Body = new TestQueryResponse 
      { 
       TopicItems = result; 
      } 
     } 
    } 


private string ParamsToXml(Dictionary<string, string> nvc) 
{ 
     //TODO: Refactor 
     StringBuilder sb = new StringBuilder(); 

     sb.Append("<params>"); 
     foreach (KeyValuePair<string, string> param in nvc) 
     { 
      sb.Append("<param>"); 
      sb.Append("<" + param.Key + ">"); 
      sb.Append(param.Value); 
      sb.Append("</" + param.Key + ">"); 
      sb.Append("</param>"); 
     } 
     sb.Append("</params>"); 

     return sb.ToString(); 
} 

Tuttavia potrei avere bisogno di farlo nel primo modo. Per esempio.

public TestQueryResponseMessage TestQuery(TestQueryRequestMessage message) 
{ 
     string xml = string.Format("<params><TestParameter>{0}</TestParameter></params>",message.Body.TestParameter) 

     var result = Repository.ExecuteQuery("TestQuery", xml); 

     return new TestQueryResponseMessage 
     { 
      Body = new TestQueryResponse 
      { 
        TopicItems = result; 
      } 
     } 
} 

Cosa consiglia il hivemind?

+1

Le cose come string.Format non sono adatte alla creazione di xml, in quanto vi sono regole di escape complesse che devono essere seguite. XmlWriter sarebbe un'alternativa ragionevole per il caso del dizionario, ma considera l'oggetto orientato all'approccio discusso di seguito. –

risposta

6

Se è necessario utilizzare xml; poi invece di passare intorno ad un dizionario, userei una classe che rappresenta tali dati, e utilizzare XmlSerializer a prenderlo come xml:

[Serializable, XmlRoot("args")] 
public class SomeArgs { 
    [XmlElement("foo")] public string Foo { get; set; } 
    [XmlAttribute("bar")] public int Bar { get; set; } 
} 
... 
SomeArgs args = new SomeArgs { Foo = "abc", Bar = 123 }; 
XmlSerializer ser = new XmlSerializer(typeof(SomeArgs)); 
StringWriter sw = new StringWriter(); 
ser.Serialize(sw, args); 
string xml = sw.ToString(); 

Questo rende molto più facile da gestire, che argomenti si applica ai quali query, in un modo orientato agli oggetti. Significa anche che non devi fare il tuo escape xml ...

+0

Penso che tu abbia ragione, grazie. Stavo cercando di farlo andare rapidamente con un'esplosione di classe minima, ma posso vedere che si trasformerà in un disordine irraggiungibile in questo modo. –

+0

@Marc Gravell: Consiglieresti lo stesso approccio o un approccio diverso con VS2010/.Net 4.0? – FMFF

+0

@FMFF Cerco di evitare che XML nel DB sia onesto –

0

Inserisco il codice di costruzione xml all'interno dell'oggetto dominio. In questo modo, puoi chiamare obj.GetXML() dal servizio Web o dal livello dati.

+0

Non trovo che "GetXml()" debba essere chiamato direttamente da "obj". Non appartiene a questo. Il tipo di "obj" dovrebbe fare ciò che dovrebbe, a meno che non lavori per formattare e esportare XML. – Sung

+0

si può fare lo stesso con un metodo di estensione, in questo modo non modificare l'oggetto dominio –

1

si potrebbe utilizzare una classe di serializzazione degli oggetti come questo

public class Serialization 
    { 
     /// <summary> 
     /// Serializes the object. 
     /// </summary> 
     /// <param name="myObject">My object.</param> 
     /// <returns></returns> 
     public static XmlDocument SerializeObject(Object myObject) 
     { 
      XmlDocument XmlObject = new XmlDocument(); 
      String XmlizedString = string.Empty; 

      try 
      {     
       MemoryStream memoryStream = new MemoryStream(); 
       XmlSerializer xs = new XmlSerializer(myObject.GetType()); 
       XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); 
       xs.Serialize(xmlTextWriter, myObject); 
       memoryStream = (MemoryStream)xmlTextWriter.BaseStream; 
       XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());     
      } 
      catch (Exception e) 
      { 
       System.Console.WriteLine(e); 
      } 
      XmlObject.LoadXml(XmlizedString); 
      return XmlObject;    
     } 

     /// <summary> 
     /// Deserializes the object. 
     /// </summary> 
     /// <typeparam name="T"></typeparam> 
     /// <param name="XmlizedString">The p xmlized string.</param> 
     /// <returns></returns> 
     public static T DeserializeObject<T>(String XmlizedString) 
     { 
      XmlSerializer xs = new XmlSerializer(typeof(T)); 
      MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(XmlizedString)); 
      //XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8); 
      Object myObject = xs.Deserialize(memoryStream); 
      return (T)myObject; 
     } 

     /// <summary> 
     /// To convert a Byte Array of Unicode values (UTF-8 encoded) to a complete String. 
     /// </summary> 
     /// <param name="characters">Unicode Byte Array to be converted to String</param> 
     /// <returns>String converted from Unicode Byte Array</returns> 
     private static String UTF8ByteArrayToString(Byte[] characters) 
     { 
      UTF8Encoding encoding = new UTF8Encoding(); 
      String constructedString = encoding.GetString(characters); 
      return (constructedString); 
     } 



     /// <summary> 
     /// Converts the String to UTF8 Byte array and is used in De serialization 
     /// </summary> 
     /// <param name="pXmlString"></param> 
     /// <returns></returns> 
     private static Byte[] StringToUTF8ByteArray(String pXmlString) 
     { 
      UTF8Encoding encoding = new UTF8Encoding(); 
      Byte[] byteArray = encoding.GetBytes(pXmlString); 
      return byteArray; 
     } 
    } 

allora non c'è bisogno di costruire l'XML a mano, più si può utilizzare questo con qualsiasi elemento di trasformare utilizzando XSLT

+2

Che (MemoryStream, Encoding, ecc.) È il modo più difficile di costruire l'xml; basta usare un StringWriter ... molto più semplice e più efficiente (nessuna codifica, nessun byte [], ecc.) –

3

Una volta che usi la soluzione di Bob The Janitor e hai il tuo XML.

Creare la stored procedure con un parametro XML. Quindi, a seconda di quanto XML hai e di cosa stai facendo, puoi usare Xquery o OpenXML per distruggere il documento XML. Estrai i dati ed esegui l'azione giusta. Questo esempio è di base e pseudocodice ma dovresti avere l'idea.

CREATE PROCEDURE [usp_Customer_INS_By_XML] 
@Customer_XML XML 
AS 
BEGIN 
EXEC sp_xml_preparedocument @xmldoc OUTPUT, @Customer_XML 

--OPEN XML example of inserting multiple customers into a Table. 
INSERT INTO CUSTOMER 
(
First_Name 
Middle_Name 
Last_Name 
) 
SELECT 
First_Name 
,Middle_Name 
,Last_Name 
FROM OPENXML (@xmldoc, '/ArrayOfCustomers[1]/Customer',2) 
WITH(
First_Name VARCHAR(50) 
,Middle_Name VARCHR(50) 
,Last_Name VARCHAR(50) 
) 

EXEC sp_xml_removedocument @xmldoc 
END 
Problemi correlati