最近练习一下 Oracle11g XML 类型的数据、看看这东西到底怎么样
xml 类型很久就有了一直没有关注,有时间正好看看;
这次学习要做的事情
1、设计一个C# 类来生成 XML Schema (XML 架构)
先设计类,然后由类生成表可能是有很多人蒙昧以求的;正好和 ORM 相反
最主要的 XML 架构可以用来约束数据库中的;XML 的有效性
2、基于上一步的 XML Schema 我们创建一个数据表、并包含这个和上边 C# 类对应的的 XML 类型;
3、插入一些数据;
4、改变 C# 的类重新生成 Schema 在更新数据库中的 Schema
这步假设业务变更看看,更改如何进行,是否方便等
5、用 C# 写一个网页,显示这些数据;
6、阶段性总结
好开始:
一、设计一个C# 类来生成 XML Schema类代码:类如下

Code
namespace Model
{
/// <summary>
/// 电话
/// </summary>
public class Phone
{
string _code;
/// <summary>
/// 电话号
/// </summary>
public string Code
{
get { return _code; }
set { _code = value; }
}
PhoneType _type;
public PhoneType Type
{
get { return _type; }
set { _type = value; }
}
}
/// <summary>
/// 电话类型
/// </summary>
public enum PhoneType
{
[XmlEnum(Name = "未知")] //XML 序列化用的名称
Unknown,
[XmlEnum(Name = "移动")]
Mobile,
[XmlEnum(Name = "固定")]
Fixed,
}
/// <summary>
/// 电话集合
/// </summary>
[XmlRoot("Phones")]
public class Phones : List<Phone>
{
public void Add(string code, PhoneType type)
{
base.Add(new Phone() { Code = code, Type = type });
}
}
}
3个类:电话、电话类型(枚举)、电话类型集合;
以 Phones 类生成 Schema ,用 .net sdk 的 xsd.exe 或自己写代码都可以生成的、我就不多说了;
Schema 这东西如果纯手写也是劳动量巨大的;谢谢.net 为我们提供这个功能吧;
Schema 如下 :

Code
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Phones" nillable="true" type="ArrayOfPhone" />
<xs:complexType name="ArrayOfPhone">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Phone" nillable="true" type="Phone" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Phone">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Code" type="xs:string" />
<xs:element minOccurs="1" maxOccurs="1" name="Type" type="PhoneType" />
</xs:sequence>
</xs:complexType>
<xs:simpleType name="PhoneType">
<xs:restriction base="xs:string">
<xs:enumeration value="未知" />
<xs:enumeration value="移动" />
<xs:enumeration value="固定" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
二、我们创建一个数据表、并包含这个和上边 C# 类对应的的 XML 类型;2.1 注册架构:

Code
BEGIN
-- 注册架构
DBMS_XMLSCHEMA.registerschema(schemaurl => 'http://www.OracleDemo.com/Phones.xsd',
schemadoc => '<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Phones" nillable="true" type="ArrayOfPhone" />
<xs:complexType name="ArrayOfPhone">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="unbounded" name="Phone" nillable="true" type="Phone" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="Phone">
<xs:sequence>
<xs:element minOccurs="0" maxOccurs="1" name="Code" type="xs:string" />
<xs:element minOccurs="1" maxOccurs="1" name="Type" type="PhoneType" />
</xs:sequence>
</xs:complexType>
<xs:simpleType name="PhoneType">
<xs:restriction base="xs:string">
<xs:enumeration value="未知" />
<xs:enumeration value="移动" />
<xs:enumeration value="固定" />
</xs:restriction>
</xs:simpleType>
</xs:schema>',
local => TRUE,
gentypes => TRUE,
genbean => FALSE,
gentables => TRUE);
END;
--会建立 xml 描述的【Oracle自定义类型】
-- 如果用Oracle 工具查看 Types 下会出现一些如 Phone***_T,phone***_coll,ArrayOfPhone***_T 类似名称的 【Oracle自定义类型】
-- 结构就和xml schema 是一样
-- gentables => TRUE 还会建立一些表;
-- 如 create table Phones721_TAB of SYS.XMLTYPE --物理表
-- create table SYS_NTyIVemDaJQXqHZgjqYv+haQ== of Phone711_T --自定义类型表
2.2 创建表

Code
CREATE TABLE XML_USER_INFO (
NPK integer,
USER_NAME NVARCHAR2(50),
Phones XMLType,
primary key (NPK)
)
XMLTYPE COLUMN Phones STORE AS OBJECT RELATIONAL --以对象关系方式建立,而不是二进制
XMLSCHEMA "http://www.OracleDemo.com/Phones.xsd"
ELEMENT "Phones"
VARRAY Phones.XMLDATA."Phone" STORE AS TABLE XML_USER_INFO_XMLNT01 --将xml中 Phones/Phone 定义为一个数组嵌套表
/
-- 返回:成功
-- 这时 oracle 还会建立一个 XML_USER_INFO_XMLNT01 的【嵌套表】
我建立了一个叫 XML_USER_INFO 的表,这个东西假设为一个用户信息表(真正的用户信息不可能这么少列的)
Oracle 建立XMLType 时可以指定以二进制或对象关系方式建立xml 类型,
我这里选择 STORE AS OBJECT RELATIONAL 据说可以提高性能,等待考证
下一面我要给 Phones/Phone 下加一些约束所以将 Phone 定义为一个数组嵌套表;说白了就是定义一个表里面都放置 Phone 类型
2.3 定义约束

Code
ALTER TABLE XML_USER_INFO_XMLNT01
ADD constraint PK_XML_USER_INFO_XMLNT01 primary key (NESTED_TABLE_ID, "Code")
就是每个人的电话号码不能重复; 数据库里的东西要是没有约束是很郁闷的,这里也试验一下这个问题;
constraint PK_XML_USER_INFO_XMLNT01 可以省略,因为有名字比较容易从异常中看出到底是什么列出错,我一般都会加上这个
除非一个表就一个主键;
遗憾的是集合类型的元素、不能加外键(就是说如果是 Phones 的属性是可以加外键的 Phone属性,如电话号码,类型什么的就不行,必须和数据库表一行能对应上的才可以加外键否则只能用 schema 约束);
外键的例子以后在说吧;
2.4 本步骤总结
比较满意、虽然SQL 代码很多不过,schema 是类生成的、能够节省一些设计时间,不过学习成本是必须的;
XMLType 的 schema 并不是必须的,不过没有约束,关系对数据库来说,时间长了是不好维护的尤其是后来人;
三、插入一些数据3.1 插入数据

Code
INSERT INTO XML_USER_INFO VALUES (1,'用户1'
,XMLType('<Phones xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http:[url]www.w3.org/2001/XMLSchema[/url]">
<Phone>
<Code>13940588000</Code>
<Type>移动</Type>
</Phone>
<Phone>
<Code>024-22222222-1</Code>
<Type>固定</Type>
</Phone>
<Phone>
<Code>8788888</Code>
<Type>未知</Type>
</Phone>
</Phones>'
)
)
/
3.2 测试约束有效性(在Type改小灵通)

Code
INSERT INTO XML_USER_INFO VALUES (2,'用户2'
,XMLType('<Phones xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http:[url]www.w3.org/2001/XMLSchema[/url]">
<Phone>
<Code>13940588000</Code>
<Type>移动</Type>
</Phone>
<Phone>
<Code>13940588000</Code>
<Type>固定</Type>
</Phone>
<Phone>
<Code>8788888</Code>
<Type>小灵通</Type>
</Phone>
</Phones>'
)
)
-- 返回错误:ORA-31038: enumeration 值无效: "小灵通"
-- 证明 PhoneType 的 XMLSchema 约束是有效的(废话);
/
….插入我就不多写了都这模样
注意:大家可以看出xmltype这里的数据,就是 Phones 对象xml序列化后的的样子
也就是说我们可以比较方便把类直接插入数据库,如果用平面表这里要执行 1*n次的 insert
代码例子我就不提供了先,因为太简单了 XMLType( :XMLString ) 然后给对象序列化了
给到 :XMLString 参数里就可以了;
3.3 本步骤总结
如果开发的话,可以节省一些语句;尤其适合那种,子表数据一次插入很少的情况
而且用 select 读取的时候,应该可以直接反序列化为对象
能省去往实体类赋值的代码量;
(文/flashelf 出处/博客园)
您可能对 [C#] 的这些文章也感兴趣: