2009-04-14 6 views
6

J'ai besoin de passer des paramètres en Xml à mes procédures stockées.Passage de paramètres en XML à une procédure stockée

J'ai un service WCF dans le niveau intermédiaire qui effectue des appels à ma couche de données qui à son tour transmet la demande à la procédure stockée appropriée.

La conception est que le service WCF est responsable de la construction du fichier XML à transmettre au référentiel. Je me demande simplement si je dois garder le contrôle des paramètres contenus dans le Xml dans le niveau intermédiaire ou utiliser un dictionnaire construit par le client que je convertis ensuite en Xml dans le niveau intermédiaire?

Au moment où je suis allé pour ce dernier - par exemple:

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(); 
} 

Cependant, je pourrais avoir besoin de faire de la première manière. Par exemple.

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; 
      } 
     } 
} 

Que recommande le hivemind?

+1

Des choses comme string.Format ne sont pas adaptés à la création de xml, car il y a des règles complexes s'échappant qui doivent être suivies. XmlWriter serait une alternative raisonnable pour le cas du dictionnaire, mais considérons que l'objet orienté est discuté ci-dessous. –

Répondre

6

Si vous devez utiliser xml; alors plutôt que de passer autour d'un dictionnaire, j'utiliser une classe qui représente les données, et utiliser XmlSerializer chercher comme 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(); 

Cela le rend beaucoup plus facile à gérer que les arguments auxquels appliquer les requêtes, en un moyen orienté objet. Cela signifie également que vous n'avez pas à faire votre propre échappement xml ...

+0

Je pense que vous avez raison merci. J'essayais de le faire rapidement avec une explosion de classe minime, mais je peux voir que ça va se transformer en un gâchis impossible à maintenir de cette façon. –

+0

@Marc Gravell: Recommanderiez-vous la même approche ou une approche différente avec VS2010/.Net 4.0? – FMFF

+0

@FMFF J'essaie d'éviter XML dans la BD pour être honnête –

0

Je mettrais le code de construction de xml à l'intérieur de l'objet de domaine. De cette façon, vous pouvez simplement appeler obj.GetXML() à partir du service Web ou de la couche de données.

+0

Je ne trouve pas que "GetXml()" devrait être appelé directement par "obj". Cela n'appartient pas là. Le type de "obj" devrait faire ce qu'il est censé faire, à moins qu'il ne l'utilise pour formater et sortir le XML. – Sung

+0

vous pouvez faire la même chose avec une méthode d'extension, de cette façon vous ne modifiez pas l'objet de domaine –

1

Vous pouvez simplement utiliser une classe de sérialisation d'objets comme celui-ci

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; 
     } 
    } 

alors vous ne devez pas construire le XML à la main, plus vous pouvez l'utiliser avec un élément pour le transformer en utilisant XSLT

+2

That (MemoryStream, Encoding, etc) est la manière difficile de construire le xml; il suffit d'utiliser un StringWriter ... beaucoup plus facile, et plus efficace (pas d'encodage, pas d'octet [], etc) –

3

Une fois que vous utilisez la solution de Bob The Janitor et que vous avez votre XML.

Créez votre procédure stockée avec un paramètre XML. Ensuite, selon la quantité de XML que vous avez et ce que vous en faites, vous pouvez utiliser Xquery ou OpenXML pour détruire le document XML. Extrayez les données et effectuez la bonne action. Cet exemple est basique et ressemble à un pseudo-code mais vous devriez avoir l'idée.

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 
Questions connexes