Передача параметров в виде XML в хранимую процедуру

У меня есть требование передавать параметры в виде Xml в мои хранимые процедуры.

У меня есть служба WCF на среднем уровне, которая вызывает мой уровень данных, который, в свою очередь, перенаправляет запрос в соответствующую хранимую процедуру.

Дизайн заключается в том, что служба WCF отвечает за создание Xml для передачи в репозиторий.

Мне просто интересно, сохранять ли контроль над тем, какие параметры содержатся в Xml на среднем уровне, или использовать словарь, созданный клиентом, который я затем конвертирую в Xml на среднем уровне?

На данный момент я выбрал последнее - например:

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

Однако мне может понадобиться сделать это первым способом. Например.

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

Что советует коллективный разум?


person Rob Stevenson-Leggett    schedule 14.04.2009    source источник
comment
Такие вещи, как string.Format, не подходят для создания xml, поскольку существуют сложные правила экранирования, которым необходимо следовать. XmlWriter был бы разумной альтернативой для словаря, но рассмотрим объектно-ориентированный подход, обсуждаемый ниже.   -  person Marc Gravell    schedule 15.04.2009


Ответы (4)


Если вы должны использовать xml; то вместо того, чтобы передавать словарь, я бы использовал класс, который представляет эти данные, и использовал бы XmlSerializer для его извлечения в виде 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();

Это значительно упрощает управление тем, какие аргументы применяются к каким запросам, объектно-ориентированным способом. Это также означает, что вам не нужно делать собственное экранирование xml...

person Marc Gravell    schedule 15.04.2009
comment
Я думаю, ты прав, спасибо. Я пытался сделать это быстро с минимальным взрывом класса, но я вижу, что таким образом это превратится в неуправляемый беспорядок. - person Rob Stevenson-Leggett; 15.04.2009
comment
@Marc Gravell: Вы бы порекомендовали тот же или другой подход к VS2010/.Net 4.0? - person FMFF; 27.02.2012
comment
@FMFF, если честно, я стараюсь избегать XML в БД. - person Marc Gravell; 27.02.2012

Как только вы воспользуетесь решением Bob The Janitor, и у вас будет свой XML.

Создайте хранимую процедуру с параметром XML. Затем, в зависимости от того, сколько XML у вас есть и что вы с ним делаете, вы можете использовать Xquery или OpenXML для уничтожения XML-документа. Извлеките данные и выполните правильное действие. Этот пример является базовым и похож на псевдокод, но вы должны уловить идею.

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
person DBAndrew    schedule 15.04.2009

Вы можете просто использовать класс сериализации объекта, подобный этому

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

тогда вам не нужно создавать XML вручную, плюс вы можете использовать это с любым элементом, чтобы преобразовать его с помощью XSLT

person Bob The Janitor    schedule 15.04.2009
comment
Это (MemoryStream, Encoding и т. д.) - сложный способ создания xml; просто используйте StringWriter... намного проще и эффективнее (без кодирования, без байта [] и т. д.) - person Marc Gravell; 15.04.2009

Я бы поместил код построения xml внутри объекта домена. Таким образом, вы можете просто вызвать obj.GetXML() из веб-службы или уровня данных.

person Gulzar Nazim    schedule 14.04.2009
comment
Я не считаю, что GetXml() должен вызываться непосредственно obj. Это не место там. Тип obj должен делать то, что он должен, если только он не предназначен для форматирования и вывода XML. - person dance2die; 14.04.2009
comment
вы можете сделать то же самое с помощью метода расширения, таким образом, вы не изменяете объект домена - person Bob The Janitor; 15.04.2009