将XML多级数据作为参数传递并在存储过程中使用

时间:2017-01-23 07:28:46

标签: c# asp.net xml stored-procedures sql-server-2012

我有XML格式数据,我将从.net应用程序传递。

在SQL Server存储过程中,此数据作为XML参数传入。我想阅读并保存所需表格中的数据,例如TblOrderTblItem

在XML中,会有多个订单。每个订单都包含一个或多个项目。

需要实施操作的结构:

<?xml version="1.0" encoding="UTF-8"?>
<Orders>
  <Order>
    <B2>B2**ABIJ**0000884443**PP</B2>
    <CreateBy null="true" />
    <CreateDate>/Date(1485150414358)/</CreateDate>
    <CurrencyId>1</CurrencyId>
    <CustomerId>13</CustomerId>
    <DeliveryAddress>LIBERTY PRESS LLC</DeliveryAddress>
    <DeliveryCity>SPRINGVILLE UT 84663</DeliveryCity>
    <DeliveryCityId>0</DeliveryCityId>
    <DeliveryDate>/Date(1478750400000)/</DeliveryDate>
    <DeliveryId>14</DeliveryId>
    <DeliveryState>UT</DeliveryState>
    <DeliveryStateId>16</DeliveryStateId>
    <DeliveryType>Delivery</DeliveryType>
    <EquipmentId>4</EquipmentId>
    <Items>
      <Item>
        <CSA>false</CSA>
        <CTPAT>false</CTPAT>
        <CommodityItem>General Freight</CommodityItem>
        <CommodityItemId>0</CommodityItemId>
        <CustCommodityItem null="true" />
        <FAST>false</FAST>
        <Hazmat>false</Hazmat>
        <Height null="true" />
        <IsActive>false</IsActive>
        <ItemId>0</ItemId>
        <ItemName>Item A</ItemName>
        <Length null="true" />
        <Make null="true" />
        <Mass null="true" />
        <MassUnit null="true" />
        <Model null="true" />
        <OrderId>0</OrderId>
        <PIP>false</PIP>
        <PilotCar>false</PilotCar>
        <ReeferTemp null="true" />
        <Tarp>false</Tarp>
        <TrailerType null="true" />
        <TruckType null="true" />
        <VIN null="true" />
        <Width null="true" />
        <Year null="true" />
      </Item>
    </Items>
    <L11>L11*SYL884443*BM</L11>
    <LastUpdate>/Date(1485150414358)/</LastUpdate>
  </Order>
  <Order>
    ...
    <Items>
      <Item>
        ...
      </Item>
    </Order>
</Orders>

我想要实现的步骤是:

  • 从存储过程中读取XML参数,该参数从.net应用程序传递。
  • 循环浏览XML并将数据保存在TblOrderTblItem表格

通过以下文章:

我的想法是访问第一级(在我的情况下,订单顺序)。 继续问题,访问第二级,这将再次成为一个集合(在我的案例中是订单项目的项目)。

提前感谢您的支持

1 个答案:

答案 0 :(得分:1)

您有两种方法:

  • 您可以将XML as as is is 传递到存储过程并在T-SQL中完成所有艰苦工作
  • 您可以在C#中粉碎XML,填充适当的数据对象并使用经典数据存储。

从我提出的问题来看,您更愿意将其作为XML参数传递给存储过程。有一些事情要知道:

  • C#在内部使用 16位unicode ,SQL Server的XML也是如此。但只要包含encoding="UTF-8",您就无法将此unicode字符串强制转换为XML ...您可以将其作为VARCHAR(MAX)(不是NVARCHAR(MAX)!)传递给您,但这可能会如果涉及特殊字符,会引发麻烦。最好的是,完全删除第一行(<?xml ...?>声明)。

  • 您的XML未正确创建。这是你掌控的吗?如果你包含null="true"(通常不需要!),你应该使用xsi - 命名空间。 XML中的日期/时间值应为ISO8601。您的值(如/Date(1485150414358)/)不是SQL Server能够直接投射的格式......

尽管如此,我看到了多个<Order> - 元素和多个<Item> - 元素。您可以按如下方式阅读它们:

DECLARE @xml XML=
N'<Orders>
  <Order>
    <B2>B2**ABIJ**0000884443**PP</B2>
    <CreateBy null="true" />
    <CreateDate>/Date(1485150414358)/</CreateDate>
    <CurrencyId>1</CurrencyId>
    <CustomerId>13</CustomerId>
    <DeliveryAddress>LIBERTY PRESS LLC</DeliveryAddress>
    <DeliveryCity>SPRINGVILLE UT 84663</DeliveryCity>
    <DeliveryCityId>0</DeliveryCityId>
    <DeliveryDate>/Date(1478750400000)/</DeliveryDate>
    <DeliveryId>14</DeliveryId>
    <DeliveryState>UT</DeliveryState>
    <DeliveryStateId>16</DeliveryStateId>
    <DeliveryType>Delivery</DeliveryType>
    <EquipmentId>4</EquipmentId>
    <Items>
      <Item>
        <CSA>false</CSA>
        <CTPAT>false</CTPAT>
        <CommodityItem>General Freight</CommodityItem>
        <CommodityItemId>0</CommodityItemId>
        <CustCommodityItem null="true" />
        <FAST>false</FAST>
        <Hazmat>false</Hazmat>
        <Height null="true" />
        <IsActive>false</IsActive>
        <ItemId>0</ItemId>
        <ItemName>Item A</ItemName>
        <Length null="true" />
        <Make null="true" />
        <Mass null="true" />
        <MassUnit null="true" />
        <Model null="true" />
        <OrderId>0</OrderId>
        <PIP>false</PIP>
        <PilotCar>false</PilotCar>
        <ReeferTemp null="true" />
        <Tarp>false</Tarp>
        <TrailerType null="true" />
        <TruckType null="true" />
        <VIN null="true" />
        <Width null="true" />
        <Year null="true" />
      </Item>
    </Items>
    <L11>L11*SYL884443*BM</L11>
    <LastUpdate>/Date(1485150414358)/</LastUpdate>
  </Order>
</Orders>';

- 查询

SELECT --elements of Order
       o.value(N'(B2)[1]',N'nvarchar(max)') AS B2

      --very strange date-format...
      ,o.value(N'(CreateDate)[1]',N'nvarchar(max)') AS CreateDate
      --typed INT
      ,o.value(N'(CurrencyId)[1]',N'int') AS CurrencyId

      --more like this

      --elements of Item
      ,i.value(N'(CSA)[1]',N'nvarchar(max)') AS CSA

      --There's no need for *null="true"*
      --Query the "/text()" and the empty element will be NULL
      ,CASE WHEN i.value(N'(CustCommodityItem/@null)[1]',N'nvarchar(max)')=N'true' THEN NULL ELSE i.value(N'(CustCommodityItem)[1]',N'nvarchar(max)') END AS CustCommodityItem_complicated
      ,i.value(N'(CustCommodityItem)[1]',N'nvarchar(max)') AS CustCommodityItem_empty
      ,i.value(N'(CustCommodityItem/text())[1]',N'nvarchar(max)') AS CustCommodityItem_null


FROM @xml.nodes(N'/Orders/Order') AS A(o)
OUTER APPLY o.nodes(N'Items/Item') AS B(i)