记录生成过程 (SQLXML 4.0)

XML 大容量加载处理 XML 输入数据并为 Microsoft SQL Server 中的相应表准备记录。XML 大容量加载中的逻辑确定何时生成新记录、要将哪些子元素或属性值复制到记录的字段以及何时完成记录并可以发送到 SQL Server 以便插入。

XML 大容量加载不将整个 XML 输入数据加载到内存中,在将数据发送到 SQL Server 之前不生成完整的记录集。这是因为 XML 输入数据可能是大文档,将整个文档加载到内存代价过大。XML 大容量加载改为执行以下操作:

  1. 分析映射架构并准备必要的执行计划。

  2. 将执行计划应用到输入流中的数据。

这种顺序处理使得按特定方式提供 XML 输入数据很重要。您必须了解 XML 大容量加载是如何分析映射架构以及是如何生成记录的,这样才能为 XML 大容量加载提供映射架构以生成您所要的结果。

XML 大容量加载处理常见映射架构批注,包括列和表映射(通过使用批注显式指定或通过默认映射隐式指定)以及联接关系。

注意注意

此处假定您熟悉带批注的 XSD 或 XDR 映射架构。有关架构的详细信息,请参阅带批注的 XSD 架构简介 (SQLXML 4.0)带批注的 XDR 架构(在 SQLXML 4.0 中不推荐使用)

了解记录生成需要了解以下概念:

  • 节点作用域

  • 记录生成规则

  • 记录子集和键排序规则

  • 记录生成规则的例外情况

节点作用域

当 XML 大容量加载在 XML 输入数据流中遇到 XML 文档中的某节点(元素或属性)时,就认为是该节点“进入作用域”。对于元素节点,元素的开始标记使该元素进入作用域。对于属性节点,属性名称使该属性进入作用域。

当在结束标记(对于元素节点)或属性值结尾(对于属性节点)没有更多数据用于节点时,则表示节点离开作用域。

记录生成规则

节点(元素或属性)进入作用域时,可能从该节点生成记录。只要相关的节点在作用域中,该记录就存在。当节点离开作用域时,XML 大容量加载认为生成的记录已完成(带数据)并将它发送到 SQL Server 以便进行插入。

例如,考虑下面的 XSD 架构片段:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:sql="urn:schemas-microsoft-com:mapping-schema">
  <xsd:element name="Customer" sql:relation="Customers" >
   <xsd:complexType>
     <xsd:attribute name="CustomerID" type="xsd:string" />
     <xsd:attribute name="CompanyName" type="xsd:string" />
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

该架构指定具有 CustomerIDCompanyName 属性的 <Customer> 元素。sql:relation 批注将 <Customer> 元素映射到 Customers 表。

考虑 XML 文档的以下片段:

<Customer CustomerID="1" CompanyName="xyz" />
<Customer CustomerID="2" CompanyName="abc" />
...

将前文中所述的架构提供给 XML 大容量加载并使用 XML 数据作为输入,XML 大容量加载按以下方式处理源数据中的节点(元素和属性):

  • 第一个 <Customer> 元素的开始标记使该元素进入作用域。将此节点映射到 Customers 表。因此,XML 大容量加载为 Customers 表生成一个记录。

  • 在架构中,将 <Customer> 元素的所有属性映射到 Customers 表的列。这些属性进入作用域时,XML 大容量加载将它们的值复制到父作用域已生成的客户记录。

  • XML 大容量加载到达 <Customer> 元素的结束标记时,该元素离开作用域。这将导致 XML 大容量加载认为该记录已完成并将其发送到 SQL Server。

XML 大容量加载为每个后续的 <Customer> 元素执行此过程。

重要说明重要提示

在此模型中,由于是在到达结束标记(或节点离开作用域)时插入记录,因此必须定义节点作用域内与该记录相关的所有数据。

记录子集和键排序规则

指定使用 <sql:relationship> 的映射架构时,“子集”一词指针对关系的外键关系生成的记录集。在下面的示例中,CustOrder 记录是针对外键关系 <sql:relationship> 生成的。

例如,假定一个数据库包含以下各表:

  • Cust (CustomerID, CompanyName, City)

  • CustOrder (CustomerID, OrderID)

CustOrder 表中的 CustomerID 是外键,它引用 Cust 表中的 CustomerID 主键。

现在,请考虑在以下带批注的 XSD 架构中指定的 XML 视图。此架构使用 <sql:relationship> 指定 Cust 表和 CustOrder 表之间的关系。

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:sql="urn:schemas-microsoft-com:mapping-schema">
<xsd:annotation>
  <xsd:appinfo>
    <sql:relationship name="CustCustOrder"
          parent="Cust"
          parent-key="CustomerID"
          child="CustOrder"
          child-key="CustomerID" />
  </xsd:appinfo>
</xsd:annotation>

  <xsd:element name="Customers" sql:relation="Cust" >
   <xsd:complexType>
     <xsd:sequence>
       <xsd:element name="CustomerID"  type="xsd:integer" />
       <xsd:element name="CompanyName" type="xsd:string" />
       <xsd:element name="City"        type="xsd:string" />
       <xsd:element name="Order" 
                          sql:relation="CustOrder"
                          sql:relationship="CustCustOrder" >
         <xsd:complexType>
          <xsd:attribute name="OrderID" type="xsd:integer" />
         </xsd:complexType>
       </xsd:element>
     </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

下面给出了示例 XML 数据和创建工作示例的步骤。

  • 当 XML 数据文件中的 <Customer> 元素节点进入作用域时,XML 大容量加载为 Cust 表生成一个记录。然后,当 <CustomerID><CompanyName><City> 子元素进入作用域时,XML 大容量加载从这些子元素复制所需的列值(CustomerID、CompanyName 和 City)。

  • <Order> 元素节点进入作用域时,XML 大容量加载为 CustOrder 表生成一个记录。XML 大容量加载将 OrderID 属性的值复制到此记录。CustomerID 列所需的值从 <Customer> 元素的 <CustomerID> 子元素获取。除非在 <Order> 元素中指定了 CustomerID 属性,否则 XML 大容量加载使用 <sql:relationship> 中指定的信息来获取此记录的 CustomerID 外键值。一般规则是:如果子元素显式指定外键属性的值,则 XML 大容量加载使用该值,而不通过使用指定的 <sql:relationship> 来获取父元素的值。当此 <Order> 元素节点离开作用域时,XML 大容量加载将记录发送到 SQL Server,然后以同样的方式处理所有后续的 <Order> 元素节点。

  • 最后,<Customer> 元素节点离开作用域。此时,XML 大容量加载将客户记录发送到 SQL Server。XML 大容量加载为 XML 数据流中的所有后续客户执行此过程。

以下是有关映射架构的两点结论:

  • 当架构满足“包容”规则(例如,在相关的 <Customer><Order> 元素节点的作用域内定义了与客户和订单关联的所有数据)时,大容量加载成功。

  • 在描述 <Customer> 元素时,按适当的顺序指定其子元素。在本示例中,在 <Order> 子元素之前指定 <CustomerID> 子元素。这意味着在输入 XML 数据文件中,当 <Order> 元素进入作用域时,将 <CustomerID> 元素值作为外键值提供。首先指定键属性,此即“键排序规则”。

    如果在 <Order> 子元素之后指定 <CustomerID> 子元素,则当 <Order> 元素进入作用域时,该值不可用。接着读取 </Order> 结束标记时,将 CustOrder 表的记录视为完成并将其插入 CustOrder 表,其中将 NULL 值作为 CustomerID 列的值,而这不是我们想要的结果。

创建工作示例

  1. 将在该示例中提供的架构另存为 SampleSchema.xml。

  2. 创建以下表:

    CREATE TABLE Cust (
                  CustomerID     int         PRIMARY KEY,
                  CompanyName    varchar(20) NOT NULL,
                  City           varchar(20) DEFAULT 'Seattle')
    GO
    CREATE TABLE CustOrder (
                 OrderID        int         PRIMARY KEY,
                 CustomerID     int         FOREIGN KEY REFERENCES                                          Cust(CustomerID))
    GO
    
  3. 将以下示例 XML 输入数据另存为 SampleXMLData.xml:

    <ROOT>
      <Customers>
        <CustomerID>1111</CustomerID>
        <CompanyName>Hanari Carnes</CompanyName>
        <City>NY</City> 
        <Order OrderID="1" />
        <Order OrderID="2" />
      </Customers>
    
      <Customers>
        <CustomerID>1112</CustomerID>
        <CompanyName>Toms Spezialitten</CompanyName>
        <City>LA</City>
        <Order OrderID="3" />
      </Customers>
      <Customers>
        <CustomerID>1113</CustomerID>
        <CompanyName>Victuailles en stock</CompanyName>
        <Order OrderID="4" />
    </Customers>
    </ROOT>
    
  4. 若要执行 XML 大容量加载,请保存并执行以下 Microsoft Visual Basic Scripting Edition (VBScript) 示例 (BulkLoad.vbs):

    set objBL = CreateObject("SQLXMLBulkLoad.SQLXMLBulkload.4.0")
    objBL.ConnectionString = "provider=SQLOLEDB;data source=localhost;database=tempdb;integrated security=SSPI"
    objBL.ErrorLogFile = "c:\error.log"
    objBL.CheckConstraints = True
    objBL.Execute "c:\SampleSchema.xml", "c:\SampleXMLData.xml"
    set objBL=Nothing
    

记录生成规则的例外情况

如果节点属于 IDREF 或 IDREFS 类型,则在它进入作用域时,XML 大容量加载不为该节点生成记录。您必须确保在架构的同一位置存在记录的完整描述。忽略 dt:type="nmtokens" 批注,就像忽略 IDREFS 类型一样。

例如,考虑以下描述 <Customer><Order> 元素的 XSD 架构。<Customer> 元素包括属于 IDREFS 类型的 OrderList 属性。<sql:relationship> 标记指定客户和订单列表之间的一对多关系。

以下是架构:

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns:sql="urn:schemas-microsoft-com:mapping-schema">
<xsd:annotation>
  <xsd:appinfo>
    <sql:relationship name="CustCustOrder"
                 parent="Cust"
                 parent-key="CustomerID"
                 child="CustOrder"
                 child-key="CustomerID" />
  </xsd:appinfo>
</xsd:annotation>

  <xsd:element name="Customers" sql:relation="Cust" >
   <xsd:complexType>
    <xsd:attribute name="CustomerID" type="xsd:integer" />
    <xsd:attribute name="CompanyName" type="xsd:string" />
    <xsd:attribute name="City" type="xsd:string" />
    <xsd:attribute name="OrderList" 
                       type="xsd:IDREFS" 
                       sql:relation="CustOrder" 
                       sql:field="OrderID"
                       sql:relationship="CustCustOrder" >
    </xsd:attribute>
  </xsd:complexType>
 </xsd:element>

  <xsd:element name="Order" sql:relation="CustOrder" >
   <xsd:complexType>
    <xsd:attribute name="OrderID" type="xsd:string" />
    <xsd:attribute name="CustomerID" type="xsd:integer" />
    <xsd:attribute name="OrderDate" type="xsd:date" />
  </xsd:complexType>
 </xsd:element>
</xsd:schema>

由于大容量加载忽略 IDREFS 类型的节点,因此当 OrderList 属性节点进入作用域时不生成记录。如果要将订单记录添加到 Orders 表,必须在架构中的某个地方描述这些订单。在此架构中,指定 <Order> 元素以确保 XML 大容量加载将订单记录添加到 Orders 表。<Order> 元素描述填充 CustOrder 表的记录所需的所有属性。

您必须确保 <Customer> 元素中的 CustomerIDOrderID 值与 <Order> 元素中的值匹配。由您负责维护引用完整性。

测试工作示例

  1. 创建以下表:

    CREATE TABLE Cust (
                  CustomerID     int          PRIMARY KEY,
                  CompanyName    varchar(20)  NOT NULL,
                  City           varchar(20)  DEFAULT 'Seattle')
    GO
    CREATE TABLE CustOrder (
                  OrderID        varchar(10) PRIMARY KEY,
                  CustomerID     int         FOREIGN KEY REFERENCES                                          Cust(CustomerID),
                  OrderDate      datetime DEFAULT '2000-01-01')
    GO
    
  2. 将在该示例中提供的映射架构另存为 SampleSchema.xml。

  3. 将以下示例 XML 数据另存为 SampleXMLData.xml:

    <ROOT>
      <Customers CustomerID="1111" CompanyName="Sean Chai" City="NY"
                 OrderList="Ord1 Ord2" />
      <Customers CustomerID="1112" CompanyName="Dont Know" City="LA"
                 OrderList="Ord3 Ord4" />
      <Order OrderID="Ord1" CustomerID="1111" OrderDate="1999-01-01" />
      <Order OrderID="Ord2" CustomerID="1111" OrderDate="1999-02-01" />
      <Order OrderID="Ord3" CustomerID="1112" OrderDate="1999-03-01" />
      <Order OrderID="Ord4" CustomerID="1112" OrderDate="1999-04-01" />
    </ROOT>
    
  4. 若要执行 XML 大容量加载,请保存并执行此 VBScript 示例 (SampleVB.vbs):

    set objBL = CreateObject("SQLXMLBulkLoad.SQLXMLBulkload.4.0")
    objBL.ConnectionString = "provider=SQLOLEDB;data source=localhost;database=tempdb;integrated security=SSPI"
    objBL.ErrorLogFile = "c:\error.log"
    objBL.CheckConstraints=True
    objBL.Execute "c:\SampleSchema.xml", "c:\SampleXMLData.xml"
    set objBL=Nothing