作者:Mark A. Williams了解如何将 xml 与 Oracle 数据库、Oracle XML DB 和 Oracle Data PRovider for .NET 结合使用。 许多开发人员已经意识到,并且更多的开发人员正开始意识到 Oracle 数据库与 .NET 应用程序结合将形成了一个强大的组合。Oracle 数据库众多强大特性之一就是能够使用 XML。利用 Oracle Data Provider for .NET (ODP.NET) 和 Oracle XML DB,通过 Visual Studio.NET 应用程序在 Oracle 数据库中使用 XML 数据就和使用传统数据类型一样轻易。(关于使用 Oracle 进行一般的 .NET 开发的介绍,请参见 John Paul Cook 的文章“在 Oracle 数据库上构建 .NET 应用程序”。关于使用 XML 和 Oracle Data Provider for .NET. 的其他示例,请参见“ODP.NET 的 XML 支持”页面。) 本文介绍了利用 ODP.NET 和 Visual Studio .NET 在 Oracle 数据库中使用 XML 数据的基础知识,并非凡介绍了
将 XML 模式加载到数据库中
将 XML 实例文档加载到数据库中
创建在 XML 数据上执行 DML 操作的 .NET 应用程序。
为了成功实施本文中的代码,您需要能够访问安装了 XML DB 的 Oracle9i Release 2 或更高版本的数据库、Visual Studio.NET、Oracle 10g 客户端软件和 ODP.NET 10g。(Oracle 数据库 10g 下载包括 ODP.NET。) 在本文中,我创建了一个名为“OTNXML”的数据库用户来演示 XML 数据的使用。假如您没有足够的权限在数据库中创建拥有相应权限的用户,那么您需要与您的数据库治理员协作来完成这个任务。我将本文分解为一系列易于理解的步骤,并从创建数据库用户开始。 注重:创建新用户不是严格必需的 — 假如您已经有了一个拥有与第 1 步中列出的权限(或更高权限)的用户,那么您可以在本文中可以使用该用户。当然,您也可以为现有用增加缺少的权限。例如,OE 用户(Oracle 示例模式的一部分)拥有除 create any Directory 和 drop any directory 权限外的所有必要权限。第 1 步:创建数据库用户 为了为本文创建数据库用户,请使用 SQL*Plus 以治理用户(拥有 DBA 角色的用户)身份登录数据库,并执行以下语句: -- create the database user-- adjust tablespace names as necessary for your environmentcreate user otnxml identified by demodefault tablespace userstemporary tablespace tempquota unlimited on users;一旦创建了用户,则授予其相应的权限和角色。我选择了仅授予必要的系统权限,而不是授予“传统的”connect 和 resource 角色。 -- grant system privileges and roles to the usergrant create session,alter session,create table,create trigger,create type,create any directory,drop any directory,xdbadminto otnxml;虽然这些权限大部分您都应当很熟悉,以下摘要用来强调它们的目的和指出它们在本文中的用途:
create any directory— 该权限答应用户创建目录对象。目录对象将用来将 XML 实例文档加载到数据库中。这是一种非常强大的权限,应当仅授予可信任的用户。因为目录对象存在于数据库内部的系统命名空间中,因此必须使用“any”要害字。没有用户级的“create directory”权限。
drop any directory— 该权限是与 create any directory 权限相对应的权限。它答应用户删除目录对象。与 create any directory 权限类似,由于其系统级属性,该权限应当仅授予可信任的用户。
xdbadmin role — 该权限答应用户在 XML DB 引擎中创建目录
注重:由于 create any directory 和 drop any directory 权限提升的权力,您可能希望在完成本文之后撤销这些权限(假如您不删除用户的话)。您可能还希望删除您将创建的目录对象。 第 2 步:创建 XML 模式 因为 XML 模式文档是基于文本的文档,因此您可以使用任何文本编辑器来创建它。还有各种工具可以图形化地创建和处理该模式文档。然而,为了使本文集中笔墨介绍通过 .NET 在 Oracle 数据库内部使用 XML,而非介绍 XML 编辑和治理工具,我使用了 Notepad 来创建下面这个简单的模式文件,我将其命名为“Player.xsd”。该模式和相关的数据代表一个简单的“player”实体,例如足球队的一名运动员。 <?xml version="1.0"?><xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:xdb="http://xmlns.oracle.com/xdb"xdb:storeVarrayAsTable="true"version="1.0" ><xsd:element name="Player" xdb:defaultTable="PLAYER"><xsd:complexType xdb:SQLType="PLAYER_T"><xsd:sequence><xsd:element name="PlayerName" type="xsd:string" minOccurs="1"xdb:SQLName="PLAYER_NAME" /><xsd:element name="PlayerPosition" type="xsd:string" minOccurs="1"xdb:SQLName="PLAYER_POSITION" /><xsd:element name="PlayerNumber" type="xsd:positiveInteger"minOccurs="1" xdb:SQLName="PLAYER_NUMBER" /><xsd:element name="PlayerClub" type="xsd:string" minOccurs="1"xdb:SQLName="PLAYER_CLUB" /></xsd:sequence></xsd:complexType></xsd:element></xsd:schema>XML 模式文档是基本的模式文档,可能有一点例外:它包含 Oracle XML DB 批注。批注是 World Wide Web Consortium (W3C) XML 模式建议的一部分,它们支持将供给商特定的信息添加到模式定义中。批注还答应覆盖 XML 类型和 SQL 类型之间的默认映射。这是批注在本模式文档中的主要用途。为了使用 XML DB 批注,必须在文档的根元素下指定命名空间。这由以下文本(摘自模式文档)来实现: xmlns:xdb="http://xmlns.oracle.com/xdb"正如您看到的那样,我决定了使用文本“xdb”作为整个模式文档命名空间的缩写标识符。为了将集合存储为嵌套表,将以下文本包含在文档根元素中。 xdb:storeVarrayAsTable="true"为了指定在数据库内部用来保存数据的表的名称,我在根元素定义中包含了以下文本: xdb:defaultTable="PLAYER"注重:默认表由 Oracle 创建,并且必须不能是现有表的名称。例如,您不能“预先创建”该表并告诉 Oracle 将数据加载到其中。 该批注指示数据库中的 XML DB 引擎:用来存储该模式所提供数据的表的名称应为“PLAYER”。其余的批注在名称和功能方面非常简单。“SQLName”批注指示表中的列名,“SQLType”批注相应地指示列数据类型或数据库类型对象。例如,以下文本指示,XML 复杂类型应当以名为“PLAYER_T”的数据库类型存储在数据库中: xdb:SQLType="PLAYER_T"第 3 步:注册 XML 模式文档 为了在数据库中的 XML DB 中注册 XML 模式文档,请将“Player.xsd”文件保存在一个您有读/写权限的文件夹中。用 XML DB 将文件加载到数据库中的方式有多种。我将利用一个目录对象和 DBMS_XMLSCHEMA PL/SQL 程序包来演示该过程。 注重:该目录对象必须代表一个数据库可访问的操作系统目录。
以 OTNXML 用户身份连接数据库,创建一个目录对象,该目录对象将代表 XML 模式和实例文档所在的操作系统目录。 -- create the directory object that represents the directory-- where the schema and instance documents residecreate directory OTNXML_DIR as 'C:/My Projects/OTN/XML Schema/XML';
使用 DBMS_XMLSCHEMA 程序包在 XML DB 中注册 XML 模式。 -- register the xml schema with xml dbbegindbms_xmlschema.registerSchema(schemaurl=>'http://localhost:8080/home/OTNXML/source/xsd/Player.xsd',schemadoc=>bfilename('OTNXML_DIR','Player.xsd'),local=>TRUE,gentypes=>TRUE,genbean=>FALSE,force=>FALSE,owner=>'OTNXML',csid=>nls_charset_id('AL32UTF8'));end;/
现在已经成功在数据库中注册了该模式,您可以查看在注册过程中为您创建的对象。这些对象名称和类型是在模式定义文件中包含的批注以及系统生成的名称和类型的一个结果。例如,在第 2 步中,您指定了复杂类型的默认类型应当存储在称为“PLAYER_T”的 Oracle 类型中。下面您可以看到 Oracle 已经为您创建了该类型。 select object_name,object_type,statusfrom user_objectsorder by object_name,object_type;Results of the statement:OBJECT_NAME OBJECT_TYPE STATUS-------------------------------- ------------------- -------EXTRADATA177_L LOB VALIDNAMESPACES178_L LOB VALIDPLAYER TABLE VALIDPLAYER$xd TRIGGER VALIDPLAYER_T TYPE VALIDSYS_C004803 INDEX VALIDSYS_XDBPD6_L LOB VALID7 rows selected.第 4 步:加载 XML 实例文档 为了演示加载 XML 实例文档,我创建了一个符合在“Player.xsd”文件中所指定模式的小文件。与“Player.xsd”文件类似,该文件同样是一个使用 Notepad 创建的简单文本文件。“Player.xml”文件的内容如下: <?xml version="1.0"?><Playerxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="http://localhost:8080/home/OTNXML/source/xsd/Player.xsd"><PlayerName>Steven Gerrard</PlayerName><PlayerPosition>Midfield</PlayerPosition><PlayerNumber>8</PlayerNumber><PlayerClub>Localhost</PlayerClub></Player>该文件通过在文档的根元素中包含以下文本被指定为 XML 实例文档: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"此外,您可以看到在文档根元素中还引用了刚才注册的模式: xsi:noNamespaceSchemaLocation="http://localhost:8080/home/OTNXML/source/xsd/Player.xsd">我选择在与模式文档相同的目录(在我的机器上为“C:/My Projects/OTN/XML Schema/XML”)中创建 XML 实例文档以重用目录对象。可用下列语句加载实例文档: insert into playervalues(XMLType (bfilename('OTNXML_DIR','Player.xml'),nls_charset_id('AL32UTF8') ));注重:请务必在加载数据后执行 commit。 为了快速验证数据是否已加载,您可以在 SQL*Plus 中输入下列语句: select object_value from player;Results of the statement:OBJECT_VALUE-------------------------------------------------------------------------------<?xml version="1.0"?><Player xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://localhost:8080/home/OTNXML/source/xsd/Player.xsd"><PlayerName>Steven Gerrard</PlayerName><PlayerPosition>Midfield</PlayerPosition><PlayerNumber>8</PlayerNumber><PlayerClub>Localhost</PlayerClub></Player>1 row selected.正如您所看到的那样,该语句生成了数据的 XML 表示(即实例文档)。 第 5 步:在 XML 数据上执行 DML 操作 您已经完成了所有的安装工作,现在该运行 Visual Studio.NET,创建一个在数据库中操作 XML 数据的应用程序了。在运行 Visual Studio.NET 之后,创建一个新的 Windows Forms 项目,然后在项目中添加一个对 Oracle Data Provider for .NET 的引用。应用程序包含一个简单的表单,该表单将用来执行以下任务:
连接数据库
检索运动员
插入运动员
更新运动员
删除运动员
我将先提供完成这些任务的代码。在提供代码之后,我将实际演示该应用程序。为了执行这些任务,请创建类似下面的一个表单: 当然,执行这些操作的第一步是创建一个到数据库的连接。我已经创建了一个表单级的字段,该字段代表连接。该字段被声明为: // C#:private OracleConnection conn;'// VB.NET:Private conn As OracleConnection该字段在表单加载事件中进行初始化(如下): // C#:private void MainForm_Load(object sender, System.EventArgs e){// create new instance of Oracle Connection classconn = new OracleConnection();}'// VB.NET:Private Sub MainForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load'// create new instance of Oracle Connection classconn = New OracleConnectionEnd SubConnect 按钮背后的代码将创建到数据库的连接。这些代码本质上相当于样板。它以您先前创建的 OTNXML 用户的身份创建一个到数据库的连接。一旦成功连接,它就将禁用 Connect 按钮,启用其余按钮(我创建这些按钮时将它们禁用了),最后显示一条消息,表明成功建立了一个连接。假如出现异常,该代码将显示一个基本消息框,指示出现了什么异常。 // C#:private void BTnConnect_Click(object sender, System.EventArgs e){Cursor.Current = Cursors.WaitCursor;// adjust the connection string as necessary for your environmentstring connstr = "User Id=OTNXML; PassWord=DEMO; Data Source=ORANET";// set the connection string value for the connection objectconn.ConnectionString = connstr;// attempt to open the connection// if failure display error message// if sUCcess display simple success messagetry {conn.Open(); }catch (Exception ex) {MessageBox.Show(this, ex.Message, application.ProductName,MessageBoxButtons.OK, MessageBoxIcon.Error); }finally {if (conn.State == ConnectionState.Open) {// disable the connect buttonbtnConnect.Enabled = false;// enable the remaining buttonsbtnGetPlayer.Enabled = true;btnInsertPlayer.Enabled = true;btnUpdatePlayer.Enabled = true;btnDeletePlayer.Enabled = true;MessageBox.Show(this, "Successfully connected to database.",Application.ProductName, MessageBoxButtons.OK,MessageBoxIcon.Information); } }Cursor.Current = Cursors.Default;}'// VB.NET:Private Sub btnConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnect.ClickCursor.Current = Cursors.WaitCursor'// adjust the connection string as necessary for your environmentDim connstr As String = "User Id=OTNXML; Password=DEMO; Data Source=ORANET"'// set the connection string value for the connection objectconn.ConnectionString = connstr'// attempt to open the connection'// if failure display error message'// if success display simple success messageTryconn.Open()Catch ex As ExceptionMessageBox.Show(Me, ex.Message, Application.ProductName,MessageBoxButtons.OK, MessageBoxIcon.Error)FinallyIf (conn.State = ConnectionState.Open) Then'// disable the connect buttonbtnConnect.Enabled = False'// enable the remaining buttonsbtnGetPlayer.Enabled = TruebtnInsertPlayer.Enabled = TruebtnUpdatePlayer.Enabled = TruebtnDeletePlayer.Enabled = TrueMessageBox.Show(Me, "Successfully connected to database.",Application.ProductName, MessageBoxButtons.OK,MessageBoxIcon.Information)End IfEnd TryCursor.Current = Cursors.DefaultEnd Sub 在与数据库连接之后,您可以检索一个运动员(比如说在上一步中加载的那个)。Get Player 按钮背后的代码将根据运动员的名称来检索运动员。检索运动员的 SQL 语句将把运动员作为关系数据进行检索,而不是检索 XML 文档本身。您将看到在代码中使用 XML 文档来插入运动员的一个示例。 // C#:private void btnGetPlayer_Click(object sender, System.EventArgs e){Cursor.Current = Cursors.WaitCursor;// build the sql statement to retrieve the xml// data as relational dataStringBuilder sbSQL = new StringBuilder();sbSQL.Append("select extractvalue(object_value, '/Player/PlayerPosition'), ");sbSQL.Append(" extractvalue(object_value, '/Player/PlayerNumber'), ");sbSQL.Append(" extractvalue(object_value, '/Player/PlayerClub') ");sbSQL.Append("from player ");sbSQL.Append("where existsNode(object_value, :1) = 1");// create an input parameter for the player nameOracleParameter p1 = new OracleParameter();p1.OracleDbType = OracleDbType.Varchar2;p1.Direction = ParameterDirection.Input;p1.Value = "/Player[PlayerName=/"" + txtPlayerName.Text + "/"]";OracleCommand cmd = new OracleCommand();cmd.CommandText = sbSQL.ToString();cmd.Connection = conn;cmd.Parameters.Add(p1);OracleDataReader dr = cmd.ExecuteReader();if (dr.Read()) {// assign the values to the text boxestxtPlayerPosition.Text = dr[0].ToString();txtPlayerNumber.Text = dr[1].ToString();txtPlayerClub.Text = dr[2].ToString();dr.Close(); }else {MessageBox.Show(this, "Player Not Found", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); }dr.Dispose();cmd.Dispose();Cursor.Current = Cursors.Default;}'// VB.NET:Private Sub btnGetPlayer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGetPlayer.ClickCursor.Current = Cursors.WaitCursor'// build the sql statement to retrieve the xml'// data as relational dataDim sbSQL As StringBuilder = New StringBuildersbSQL.Append("select extractvalue(object_value, '/Player/PlayerPosition'), ")sbSQL.Append(" extractvalue(object_value, '/Player/PlayerNumber'), ")sbSQL.Append(" extractvalue(object_value, '/Player/PlayerClub') ")sbSQL.Append("from player ")sbSQL.Append("where existsNode(object_value, :1) = 1")'// create input parameter for the player nameDim p1 As OracleParameter = New OracleParameterp1.OracleDbType = OracleDbType.Varchar2p1.Direction = ParameterDirection.Inputp1.Value = "/Player[PlayerName=""" + txtPlayerName.Text + """]"Dim cmd As OracleCommand = New OracleCommandcmd.CommandText = sbSQL.ToString()cmd.Connection = conncmd.Parameters.Add(p1)Dim dr As OracleDataReader = cmd.ExecuteReader()If (dr.Read()) Then'// assign the values to the text boxestxtPlayerPosition.Text = dr(0).ToString()txtPlayerNumber.Text = dr(1).ToString()txtPlayerClub.Text = dr(2).ToString()dr.Close()ElseMessageBox.Show(Me, "Player Not Found", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error)dr.Dispose()cmd.Dispose()Cursor.Current = Cursors.DefaultEnd IfEnd Sub 该应用程序提供了将运动员插入到数据库中的功能,Ins Player 按钮背后的代码将插入一个符合您创建并加载到 XML DB 信息库中的 XML 模式的新 XML 实例文档。在创建了 XML 实例文档之后,代码将把保存该文档的变量绑定到一个典型的 insert 语句中,执行 insert 操作,显示一条成功或异常消息。 // C#:private void btnInsertPlayer_Click(object sender, System.EventArgs e){Cursor.Current = Cursors.WaitCursor;// create the xml documentStringBuilder xmlDocument = new StringBuilder();xmlDocument.Append("<?xml version=/"1.0/"?>");xmlDocument.Append("<Player");xmlDocument.Append("xmlns:xsi=/"http://www.w3.org/2001/XMLSchema-instance/"");xmlDocument.Append("xsi:noNamespaceSchemaLocation=/"http://localhost:8080/home/OTNXML/source/xsd/Player.xsd/">");xmlDocument.Append(" <PlayerName>" + txtPlayerName.Text + "</PlayerName>");xmlDocument.Append("<PlayerPosition>" + txtPlayerPosition.Text +"</PlayerPosition>");xmlDocument.Append("<PlayerNumber>" + txtPlayerNumber.Text +"</PlayerNumber>");xmlDocument.Append(" <PlayerClub>" + txtPlayerClub.Text + "</PlayerClub>");xmlDocument.Append("</Player>");// create command object and set propertiesOracleCommand cmd = new OracleCommand();cmd.Connection = conn;cmd.CommandText = "insert into player values (:1)";// create an input parameter to hold the xml documentOracleParameter p = new OracleParameter();p.Direction = ParameterDirection.Input;p.Value = xmlDocument.ToString();cmd.Parameters.Add(p);// execute the insert// display message if failuretry {cmd.ExecuteNonQuery();MessageBox.Show(this, "Player Inserted.", Application.ProductName,MessageBoxButtons.OK, MessageBoxIcon.Information); }catch (Exception ex) {MessageBox.Show(this, ex.Message, Application.ProductName,MessageBoxButtons.OK, MessageBoxIcon.Error); }p.Dispose();cmd.Dispose();Cursor.Current = Cursors.Default;}'// VB.NET:Private Sub btnInsertPlayer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnInsertPlayer.ClickCursor.Current = Cursors.WaitCursor'// create the xml documentDim xmlDocument As StringBuilder = New StringBuilderxmlDocument.Append("<?xml version=""1.0""?>")xmlDocument.Append("<Player")xmlDocument.Append("xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""")xmlDocument.Append("xsi:noNamespaceSchemaLocation=""http://localhost:8080/home/OTNXML/source/xsd/Player.xsd"">")xmlDocument.Append("<PlayerName>" + txtPlayerName.Text + "</PlayerName>")xmlDocument.Append("<PlayerPosition>" + txtPlayerPosition.Text +"</PlayerPosition>")xmlDocument.Append("<PlayerNumber>" + txtPlayerNumber.Text +"</PlayerNumber>")xmlDocument.Append("<PlayerClub>" + txtPlayerClub.Text + "</PlayerClub>")xmlDocument.Append("</Player>")'// create command object and set propertiesDim cmd As OracleCommand = New OracleCommandcmd.Connection = conncmd.CommandText = "insert into player values (:1)"'// create an input parameter to hold the xml documentDim p As OracleParameter = New OracleParameterp.Direction = ParameterDirection.Inputp.Value = xmlDocument.ToString()cmd.Parameters.Add(p)'// execute the insert'// display message if failureTrycmd.ExecuteNonQuery()MessageBox.Show(Me, "Player Inserted.", Application.ProductName,MessageBoxButtons.OK, MessageBoxIcon.Information)Catch ex As ExceptionMessageBox.Show(Me, ex.Message, Application.ProductName,MessageBoxButtons.OK, MessageBoxIcon.Error)p.Dispose()cmd.Dispose()End TryCursor.Current = Cursors.DefaultEnd Sub 与插入运动员的代码类似,Updt Player 按钮背后的代码将创建一个 XML 实例文档,将其与 SQL 语句中的一个占位符变量绑定,并执行该语句来更新运动员。SQL 语句在 where 子句中使用运动员的名称来确定更新哪个运动员。更新实际上是用一个新的包含更新数据的 XML 实例文档替换现有的 XML 实例文档。代码完成后将显示一条简单的成功或异常消息。 // C#:private void btnUpdatePlayer_Click(object sender, System.EventArgs e){Cursor.Current = Cursors.WaitCursor;// create the xml document that contains the changesStringBuilder xmlDocument = new StringBuilder();xmlDocument.Append("<?xml version=/"1.0/"?>");xmlDocument.Append("<Player");xmlDocument.Append(" xmlns:xsi=/"http://www.w3.org/2001/XMLSchema-instance/"");xmlDocument.Append(" xsi:noNamespaceSchemaLocation=/"http://localhost:8080/home/OTNXML/source/xsd/Player.xsd/">");xmlDocument.Append(" <PlayerName>" + txtPlayerName.Text + "</PlayerName>");xmlDocument.Append(" <PlayerPosition>" + txtPlayerPosition.Text + "</PlayerPosition>");xmlDocument.Append(" <PlayerNumber>" + txtPlayerNumber.Text + "</PlayerNumber>");xmlDocument.Append(" <PlayerClub>" + txtPlayerClub.Text + "</PlayerClub>");xmlDocument.Append("</Player>");StringBuilder sbSQL = new StringBuilder();sbSQL.Append("update player ");sbSQL.Append("set object_value = :1 ");sbSQL.Append("where existsNode(object_value, :2) = 1");// create an input parameter to hold the xml documentOracleParameter p1 = new OracleParameter();p1.OracleDbType = OracleDbType.Varchar2;p1.Direction = ParameterDirection.Input;p1.Value = xmlDocument.ToString(); // create an input parameter for the player nameOracleParameter p2 = new OracleParameter();p2.OracleDbType = OracleDbType.Varchar2;p2.Direction = ParameterDirection.Input;p2.Value = "/Player[PlayerName=/"" + txtPlayerName.Text + "/"]";// create command object and set propertiesOracleCommand cmd = new OracleCommand();cmd.Connection = conn;cmd.CommandText = sbSQL.ToString();cmd.Parameters.Add(p1);cmd.Parameters.Add(p2); // execute the update// display message if failuretry {cmd.ExecuteNonQuery();MessageBox.Show(this, "Player Updated.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); }catch (Exception ex) {MessageBox.Show(this, ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); }p2.Dispose();p1.Dispose();cmd.Dispose();Cursor.Current = Cursors.Default;}'// VB.NET:Private Sub btnUpdatePlayer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUpdatePlayer.ClickCursor.Current = Cursors.WaitCursor'// create the xml document that contains the changesDim xmlDocument As StringBuilder = New StringBuilderxmlDocument.Append("<?xml version=""1.0""?>")xmlDocument.Append("<Player")xmlDocument.Append(" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""")xmlDocument.Append(" xsi:noNamespaceSchemaLocation=""http://localhost:8080/home/OTNXML/source/xsd/Player.xsd"">")xmlDocument.Append(" <PlayerName>" + txtPlayerName.Text + "</PlayerName>")xmlDocument.Append(" <PlayerPosition>" + txtPlayerPosition.Text + "</PlayerPosition>")xmlDocument.Append(" <PlayerNumber>" + txtPlayerNumber.Text + "</PlayerNumber>")xmlDocument.Append(" <PlayerClub>" + txtPlayerClub.Text + "</PlayerClub>")xmlDocument.Append("</Player>")Dim sbSQL As StringBuilder = New StringBuildersbSQL.Append("update player ")sbSQL.Append("set object_value = :1 ")sbSQL.Append("where existsNode(object_value, :2) = 1")'// create an input parameter to hold the xml documentDim p1 As OracleParameter = New OracleParameterp1.OracleDbType = OracleDbType.Varchar2p1.Direction = ParameterDirection.Inputp1.Value = xmlDocument.ToString()'// create an input parameter for the player nameDim p2 As OracleParameter = New OracleParameterp2.OracleDbType = OracleDbType.Varchar2p2.Direction = ParameterDirection.Inputp2.Value = "/Player[PlayerName=""" + txtPlayerName.Text + """]"'// create command object and set propertiesDim cmd As OracleCommand = New OracleCommandcmd.Connection = conncmd.CommandText = sbSQL.ToString()cmd.Parameters.Add(p1)cmd.Parameters.Add(p2)'// execute the update'// display message if failureTrycmd.ExecuteNonQuery()MessageBox.Show(Me, "Player Updated.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information)Catch ex As ExceptionMessageBox.Show(Me, ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error)p1.Dispose()p2.Dispose()cmd.Dispose()End TryCursor.Current = Cursors.DefaultEnd Sub 该应用程序提供的最后的 DML 操作是删除运动员的功能。与 retrieve 和 update 代码类似,这些代码使用运动员的名称作为确定对哪个运动员执行该操作的基础。 // C#:private void btnDeletePlayer_Click(object sender, System.EventArgs e){Cursor.Current = Cursors.WaitCursor;// build the delete statementStringBuilder sbSQL = new StringBuilder();sbSQL.Append("delete ");sbSQL.Append("from player ");sbSQL.Append("where existsNode(object_value, :1) = 1");// create an input parameter for the player nameOracleParameter p1 = new OracleParameter();p1.OracleDbType = OracleDbType.Varchar2;p1.Direction = ParameterDirection.Input;p1.Value = "/Player[PlayerName=/"" + txtPlayerName.Text + "/"]";// create command object and set propertiesOracleCommand cmd = new OracleCommand();cmd.Connection = conn;cmd.CommandText = sbSQL.ToString();cmd.Parameters.Add(p1);// execute the deletetry {cmd.ExecuteNonQuery();MessageBox.Show(this, "Player Deleted.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information); }catch (Exception ex) {MessageBox.Show(this, ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error); }cmd.Dispose();Cursor.Current = Cursors.WaitCursor;}'// VB.NET:Private Sub btnDeletePlayer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDeletePlayer.ClickCursor.Current = Cursors.WaitCursor'// build the delete statementDim sbSQL As StringBuilder = New StringBuildersbSQL.Append("delete ")sbSQL.Append("from player ")sbSQL.Append("where existsNode(object_value, :1) = 1")'// create an input parameter for the player nameDim p1 As OracleParameter = New OracleParameterp1.OracleDbType = OracleDbType.Varchar2p1.Direction = ParameterDirection.Inputp1.Value = "/Player[PlayerName=""" + txtPlayerName.Text + """]"'// create command object and set propertiesDim cmd As OracleCommand = New OracleCommandcmd.Connection = conncmd.CommandText = sbSQL.ToString()cmd.Parameters.Add(p1)'// execute the deleteTrycmd.ExecuteNonQuery()MessageBox.Show(Me, "Player Deleted.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Information)Catch ex As ExceptionMessageBox.Show(Me, ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error)cmd.Dispose()End TryCursor.Current = Cursors.WaitCursorEnd Sub为了清除该表单,Reset 按钮背后的代码将简单地将文本框的值设为空字符串。 // C#:private void btnReset_Click(object sender, System.EventArgs e){// "clear" the text box valuestxtPlayerName.Text = "";txtPlayerPosition.Text = "";txtPlayerNumber.Text = "";txtPlayerClub.Text = "";// assign focus to the player name text boxtxtPlayerName.Focus();}'// VB.NET:Private Sub btnReset_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnReset.Click'// "clear" the text box valuestxtPlayerName.Text = ""txtPlayerPosition.Text = ""txtPlayerNumber.Text = ""txtPlayerClub.Text = ""'// assign focus to the player name text boxtxtPlayerName.Focus()End Sub 正如您可能预料到的那样,Close 按钮背后的代码仅执行表单关闭。 // C#:private void btnClose_Click(object sender, System.EventArgs e){// simply close the formthis.Close();}'// VB.NET:Private Sub btnClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnClose.Click'// simply close the formMe.Close()End Sub表单关闭事件中的代码将检查数据库连接对象是否处于打开状态;假如是,则将关闭并删除该对象。 // C#:private void MainForm_Closing(object sender,System.ComponentModel.CancelEventArgs e){if (conn.State == ConnectionState.Open) {// close connection and dispose connection objectconn.Close();conn.Dispose();conn = null; }}'// VB.NET:Private Sub MainForm_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.ClosingIf (conn.State = ConnectionState.Open) Then'// close connection and dispose connection objectconn.Close()conn.Dispose()conn = NothingEnd IfEnd Sub第 6 步:运行应用程序 现在您已经创建和加载了 XML 模式和 XML 实例文档,并创建了应用程序,现在该看看它实际工作的情形了。当应用程序启动时,表单的初始外观将与下面类似: 在您单击 Connect 按钮之后,表单将显示一个消息框,指示成功建立连接,并且应启用了“DML 按钮”: 要查看您在第 5 步中为 XML 实例文档加载的运动员数据,请用运动员的名称(Steven Gerrard,假如您使用与我相同数据的话)填充 Player Name 文本框,并单击 Get Player 按钮: 要创建新运动员,您可以单击 Reset 按钮,然后在文本框中输入新信息,或者简单地替换现有文本: 一旦您对各种运动员属性的值感到满足,即可单击 Ins Player 按钮。包含运动员信息的新 XML 实例文档将被插入到数据库中,并显示一个消息框: 要更新运动员,您可以只要修改属性(运动员名称除外)即可。例如,我将运动员的号码更改为 100: 单击 Updt Player 按钮,更新数据库中的数据: 不幸地是,我似乎不符合 Localhost Football Club 的要求,因此我必须删除我自己。为了删除运动员,只需单击 Del Player 按钮即可: 要验证运动员是否已被删除,请单击 Reset 按钮,然后在 Player Name 文本框中输入运动员名称: 现在,单击 Get Player 按钮将显示一个消息框,指示找不到请求的运动员: 当您完成测试时,单击 Close 按钮,终止应用程序。 总结 在本文中,我向您介绍了如何在 XML DB 信息库中加载和注册 XML 模式文档,以及如何将符合模式的 XML 实例文档加载到数据库中。然后我创建了一个简单的 Windows 表单应用程序,它在 XML 数据上执行 DML 操作。最后我演练了该应用程序的使用。这些信息将使您能开始从您基于 Oracle 的 .NET 应用程序在数据库中使用 XML 数据。 Mark A. Williams 是《.NET 专家 Oracle 编程》(Apress,2004 年 11 月)的作者,目前在医疗诊断行业担任 Production DBA。他自从 Oracle 数据库的 7.0.1.16 版本起一直在使用 Oracle 产品,并且是版本 7、8、8i 和 9i 的 Oracle 认证数据库治理员专家。