Javascript 将XML格式的Web数据传递到SQL Server数据库的合理方法
在探索了几种将web数据传递到数据库进行更新的不同方法之后,我想知道XML是否是一种好的策略。数据库当前为SQL 2000。几个月后,它将转移到SQL 2005,如果需要,我将能够更改内容,但我现在需要一个SQL 2000解决方案 首先,所讨论的数据库使用。我知道这种类型的数据库通常是非常不受欢迎的,所以就这个问题而言,请接受这种情况不会改变 当前的更新方法让web服务器将值(首先转换为正确的基础类型,然后转换为sql_变量)插入临时表。然后运行一个存储过程,该过程期望临时表存在,并根据需要负责更新、插入或删除内容 到目前为止,一次只需要更新一个元素。但现在,需要能够一次编辑多个元素,还需要支持分层元素,每个元素都有自己的属性列表。下面是我手工键入的一些XML示例,以演示我的想法 请注意,在该数据库中,实体是元素,ID为0表示“创建”即插入新项Javascript 将XML格式的Web数据传递到SQL Server数据库的合理方法,javascript,sql-server,xml,asp-classic,Javascript,Sql Server,Xml,Asp Classic,在探索了几种将web数据传递到数据库进行更新的不同方法之后,我想知道XML是否是一种好的策略。数据库当前为SQL 2000。几个月后,它将转移到SQL 2005,如果需要,我将能够更改内容,但我现在需要一个SQL 2000解决方案 首先,所讨论的数据库使用。我知道这种类型的数据库通常是非常不受欢迎的,所以就这个问题而言,请接受这种情况不会改变 当前的更新方法让web服务器将值(首先转换为正确的基础类型,然后转换为sql_变量)插入临时表。然后运行一个存储过程,该过程期望临时表存在,并根据需要负责
<Elements>
<Element ID="1234">
<Attr ID="221">Value</Attr>
<Attr ID="225">287</Attr>
<Attr ID="234">
<Element ID="99825">
<Attr ID="7">Value1</Attr>
<Attr ID="8">Value2</Attr>
<Attr ID="9" Action="delete" />
</Element>
<Element ID="99826" Action="delete" />
<Element ID="0" Type="24">
<Attr ID="7">Value4</Attr>
<Attr ID="8">Value5</Attr>
<Attr ID="9">Value6</Attr>
</Element>
<Element ID="0" Type="24">
<Attr ID="7">Value7</Attr>
<Attr ID="8">Value8</Attr>
<Attr ID="9">Value9</Attr>
</Element>
</Attr>
<Rel ID="3827" Action="delete" />
<Rel ID="2284" Role="parent">
<Element ID="3827" />
<Element ID="3829" />
<Attr ID="665">1</Attr>
</Rel>
<Rel ID="0" Type="23" Role="child">
<Element ID="3830" />
<Attr ID="67"
</Rel>
</Element>
<Element ID="0" Type="87">
<Attr ID="221">Value</Attr>
<Attr ID="225">569</Attr>
<Attr ID="234">
<Element ID="0" Type="24">
<Attr ID="7">Value10</Attr>
<Attr ID="8">Value11</Attr>
<Attr ID="9">Value12</Attr>
</Element>
</Attr>
</Element>
<Element ID="1235" Action="delete" />
</Elements>
示例:模板输入名称_a678变为n1_a678(一个新元素,页面上的第一个元素,属性678)。此新元素的所有属性都使用相同的前缀n1进行标记。下一个新项目将是n2,依此类推。创建了一些隐藏的表单输入:
n1_t,value是要创建的元素的elementtype
n1_p,value是元素的父id(如果是关系)
n1_c,value是元素的子id(如果是关系)
Data.AddNew
ElementID.Value = DataID
AttrID.Value = Integerize(Matches(0).SubMatches(3))
AttrValue.Value = Request.Form(Key)
Data.Update
ElementID、AttrID和AttrValue是对记录集字段的引用。这种方法比每次使用Data.Fields(“ElementID”)值要快得多
我在元素更新字典中循环,忽略所有没有正确信息的元素,将好的元素添加到记录集中
然后调用数据更新存储过程,如下所示:
Set Cmd = Server.CreateObject("ADODB.Command")
With Cmd
Set .ActiveConnection = MyDBConn
.CommandType = adCmdStoredProc
.CommandText = "DataPost"
.Prepared = False
.Parameters.Append .CreateParameter("@ElementMetadata", adLongVarWChar, adParamInput, 2147483647, XMLFromRecordset(Element))
.Parameters.Append .CreateParameter("@ElementData", adLongVarWChar, adParamInput, 2147483647, XMLFromRecordset(Data))
End With
Result.Open Cmd ' previously created recordset object with options set
下面是执行xml转换的函数:
Private Function XMLFromRecordset(Recordset)
Dim Stream
Set Stream = Server.CreateObject("ADODB.Stream")
Stream.Open
Recordset.Save Stream, adPersistXML
Stream.Position = 0
XMLFromRecordset = Stream.ReadText
End Function
为了防止web页面需要知道,SP返回任何新元素的记录集,显示它们的页面值和创建的值(例如,我可以看到n1现在是e12346)
下面是存储过程中的一些关键片段。请注意,目前这是SQL 2000,不过我很快就能切换到2005:
CREATE PROCEDURE [dbo].[DataPost]
@ElementMetaData ntext,
@ElementData ntext
AS
DECLARE @hdoc int
--- snip ---
EXEC sp_xml_preparedocument @hdoc OUTPUT, @ElementMetaData, '<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema" />'
INSERT #ElementMetadata (ElementID, ElementTypeID, ElementID1, ElementID2)
SELECT *
FROM
OPENXML(@hdoc, '/xml/rs:data/rs:insert/z:row', 0)
WITH (
ElementID int,
ElementTypeID int,
ElementID1 int,
ElementID2 int
)
ORDER BY ElementID -- orders negative items (new elements) first so they begin counting at 1 for later ID calculation
EXEC sp_xml_removedocument @hdoc
--- snip ---
UPDATE E
SET E.ElementTypeID = M.ElementTypeID
FROM
Element E
INNER JOIN #ElementMetadata M ON E.ElementID = M.ElementID
WHERE
E.ElementID >= 1
AND M.ElementTypeID >= 1
创建过程[dbo].[DataPost]
@ElementText,
@元素数据文本
作为
声明@hdoc int
---剪断---
EXEC sp_xml_preparedocument@hdoc OUTPUT,@ElementMetaData,''
插入#ElementMetadata(ElementID、ElementTypeID、ElementID1、ElementID2)
挑选*
从…起
OPENXML(@hdoc,'/xml/rs:data/rs:insert/z:row',0)
与(
元素ID int,
ElementTypeID int,
ElementID1 int,
ElementID2 int
)
ORDER BY ElementID——首先对负项(新元素)进行排序,以便它们从1开始计数,以便以后计算ID
EXEC sp_xml_removedocument@hdoc
---剪断---
更新E
设置E.ElementTypeID=M.ElementTypeID
从…起
元素E
E.ElementID=M.ElementID上的内部联接#ElementMetadata M
哪里
E.ElementID>=1
而M.ElementTypeID>=1
以下查询不会将负新元素ID与新插入的ID进行关联:
UPDATE #ElementMetadata -- Correlate the new ElementIDs with the input rows
SET NewElementID = Scope_Identity() - @@RowCount + DataID
WHERE ElementID < 0
UPDATE#ElementMetadata——将新的elementid与输入行关联起来
SET-NewElementID=Scope_Identity()-@@RowCount+DataID
其中ElementID<0
其他基于集合的查询执行所有其他工作,包括验证属性是否被允许、是否为正确的数据类型以及插入、更新和删除元素和属性
我希望这篇简短的总结有一天对其他人有用!将ADO记录集转换为XML流对我来说是一个巨大的赢家,因为它节省了各种时间,并且已经定义了一个名称空间和模式,可以正确地得出结果
使用带有2个输入的更平坦的XML格式也比坚持将所有内容都放在一个XML流中的理想方式要容易得多。我看不出有任何理由不在SQL Server 2005中使用XML列,也没有理由不通过存储过程来完成所有工作 您可能没有时间抽象数据访问以隐藏数据模型的丑陋,所以为什么不使用XML按原样访问它呢?您可以在SQLServer中使用XQuery进行更新、查询等 现在我想起来了,您仍然可以在ASP页面和数据库之间放置一层抽象。这将允许您在将来使用XSLT将XML的结构转换为一种格式,这种格式在d语言中性能更好
CREATE PROCEDURE [dbo].[DataPost]
@ElementMetaData ntext,
@ElementData ntext
AS
DECLARE @hdoc int
--- snip ---
EXEC sp_xml_preparedocument @hdoc OUTPUT, @ElementMetaData, '<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema" />'
INSERT #ElementMetadata (ElementID, ElementTypeID, ElementID1, ElementID2)
SELECT *
FROM
OPENXML(@hdoc, '/xml/rs:data/rs:insert/z:row', 0)
WITH (
ElementID int,
ElementTypeID int,
ElementID1 int,
ElementID2 int
)
ORDER BY ElementID -- orders negative items (new elements) first so they begin counting at 1 for later ID calculation
EXEC sp_xml_removedocument @hdoc
--- snip ---
UPDATE E
SET E.ElementTypeID = M.ElementTypeID
FROM
Element E
INNER JOIN #ElementMetadata M ON E.ElementID = M.ElementID
WHERE
E.ElementID >= 1
AND M.ElementTypeID >= 1
UPDATE #ElementMetadata -- Correlate the new ElementIDs with the input rows
SET NewElementID = Scope_Identity() - @@RowCount + DataID
WHERE ElementID < 0
select x.value(N'@ID', N'int') as ID,
x.value(N'.', N'varchar(max)') as [Value]
from @x.nodes('//Element[not(@Action="delete") and not (@ID=0)]/Attr') t(x)
select x.value(N'@ID', N'int') as ID,
x.value(N'.', N'varchar(max)') as [Value]
from @x.nodes('//Element[@ID=0]/Attr') t(x);
select x.value(N'@ID', N'int') as ID
from @x.nodes('//Element[@Action="delete"]') t(x);