VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > Objective-C编程 >
  • c#操作xml数据库类型、Oracle XMLType

制作者:剑锋冷月 单位:无忧统计网,www.51stat.net
 

  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类代码:

  类如下

namespaceModel
{
  
  ///<summary>
  ///电话
  ///</summary>
  publicclassPhone
  {
    string_code;
    ///<summary>
    ///电话号
    ///</summary>
    publicstringCode
    {
      get{return_code;}
      set{_code=value;}
    }
    PhoneType_type;
    publicPhoneTypeType
    {
      get{return_type;}
      set{_type=value;}
    }    
    
  }
  ///<summary>
  ///电话类型
  ///</summary>
  publicenumPhoneType
  {
    [XmlEnum(Name="未知")]//XML序列化用的名称
    Unknown,
    [XmlEnum(Name="移动")]
    Mobile,
    [XmlEnum(Name="固定")]
    Fixed,
  
  }
  ///<summary>
  ///电话集合
  ///</summary>
  [XmlRoot("Phones")]
  publicclassPhones:List<Phone>
  {
    publicvoidAdd(stringcode,PhoneTypetype)
    {
      base.Add(newPhone(){Code=code,Type=type});
    }
    
  }
}

  3个类:电话、电话类型(枚举)、电话类型集合;

  以Phones 类生成 Schema ,用 .net sdk 的 xsd.exe 或自己写代码都可以生成的、我就不多说了;

  Schema 这东西如果纯手写也是劳动量巨大的;谢谢.net 为我们提供这个功能吧;

  Schema如下:

<xs:schemaelementFormDefault="qualified"xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xs:elementname="Phones"nillable="true"type="ArrayOfPhone"/>
 <xs:complexTypename="ArrayOfPhone">
  <xs:sequence>
   <xs:elementminOccurs="0"maxOccurs="unbounded"name="Phone"nillable="true"type="Phone"/>
  </xs:sequence>
 </xs:complexType>
 <xs:complexTypename="Phone">
  <xs:sequence>
   <xs:elementminOccurs="0"maxOccurs="1"name="Code"type="xs:string"/>
   <xs:elementminOccurs="1"maxOccurs="1"name="Type"type="PhoneType"/>
  </xs:sequence>
 </xs:complexType>
 <xs:simpleTypename="PhoneType">
  <xs:restrictionbase="xs:string">
   <xs:enumerationvalue="未知"/>
   <xs:enumerationvalue="移动"/>
   <xs:enumerationvalue="固定"/>
  </xs:restriction>
 </xs:simpleType>
</xs:schema>

  二、我们创建一个数据表、并包含这个和上边 C# 类对应的的 XML 类型;

  2.1 注册架构:

BEGIN
  --注册架构
 DBMS_XMLSCHEMA.registerschema(schemaurl=>'http://www.OracleDemo.com/Phones.xsd',
                schemadoc=>'<xs:schemaelementFormDefault="qualified"xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xs:elementname="Phones"nillable="true"type="ArrayOfPhone"/>
 <xs:complexTypename="ArrayOfPhone">
  <xs:sequence>
   <xs:elementminOccurs="0"maxOccurs="unbounded"name="Phone"nillable="true"type="Phone"/>
  </xs:sequence>
 </xs:complexType>
 <xs:complexTypename="Phone">
  <xs:sequence>
   <xs:elementminOccurs="0"maxOccurs="1"name="Code"type="xs:string"/>
   <xs:elementminOccurs="1"maxOccurs="1"name="Type"type="PhoneType"/>
  </xs:sequence>
 </xs:complexType>
 <xs:simpleTypename="PhoneType">
  <xs:restrictionbase="xs:string">
   <xs:enumerationvalue="未知"/>
   <xs:enumerationvalue="移动"/>
   <xs:enumerationvalue="固定"/>
  </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自定义类型】

 

--结构就和xmlschema是一样

 

--gentables=>TRUE还会建立一些表;

 

--如createtablePhones721_TABofSYS.XMLTYPE--物理表

 

--createtableSYS_NTyIVemDaJQXqHZgjqYv+haQ==ofPhone711_T--自定义类型表

 

  2.2 创建表

CREATEtableXML_USER_INFO(
NPKinteger,
USER_NAMENVARCHAR2(50),
PhonesXMLType,
primarykey(NPK)
)
XMLTYPECOLUMNPhonesSTOREASOBJECTRELATIONAL     --以对象关系方式建立,而不是二进制
XMLSCHEMA"http://www.OracleDemo.com/Phones.xsd"
ELEMENT"Phones"
VARRAYPhones.XMLDATA."Phone"STOREAStableXML_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 定义约束

  

  ALTERtableXML_USER_INFO_XMLNT01

   ADDconstraintPK_XML_USER_INFO_XMLNT01primarykey(NESTED_TABLE_ID,"Code")

 

  就是每个人的电话号码不能重复; 数据库里的东西要是没有约束是很郁闷的,这里也试验一下这个问题;

  constraint PK_XML_USER_INFO_XMLNT01 可以省略,因为有名字比较容易从异常中看出到底是什么列出错,我一般都会加上这个

  除非一个表就一个主键;

  遗憾的是集合类型的元素、不能加外键(就是说如果是 Phones 的属性是可以加外键的 Phone属性,如电话号码,类型什么的就不行,必须和数据库表一行能对应上的才可以加外键否则只能用 schema 约束);

  外键的例子以后在说吧;

  2.4 本步骤总结

  比较满意、虽然sql 代码很多不过,schema 是类生成的、能够节省一些设计时间,不过学习成本是必须的;

  XMLType 的 schema 并不是必须的,不过没有约束,关系对数据库来说,时间长了是不好维护的尤其是后来人;

  三、插入一些数据

  3.1 插入数据

INSERTINTOXML_USER_INFOVALUES(1,'用户1'
  ,XMLType('<Phonesxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http:www.w3.org/2001/XMLSchema">
<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改小灵通)

INSERTINTOXML_USER_INFOVALUES(2,'用户2'
  ,XMLType('<Phonesxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http:www.w3.org/2001/XMLSchema">
 <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 读取的时候,应该可以直接反序列化为对象

  能省去往实体类赋值的代码量;

  四、改变 C# 的类重新生成 Schema在更新数据库中的 Schema

  假设我们的业务更改:那个业务也不可能不变的对吧,所以测试是否容易修改也是必要的

  假设,【电话】加入了说明属性、【电话类型】加入了小灵通;集合类没更改;

  4.1 类的更改

publicclassPhone
{
  string_code;
  publicstringCode
  {
    get{return_code;}
    set{_code=value;}
  }
  PhoneType_type;
  publicPhoneTypeType
  {
    get{return_type;}
    set{_type=value;}
  }
  
  //新加入
  string_make;
  publicstringMake
  {
    get{return_make;}
    set{_make=value;}
  }
  
}
publicenumPhoneType
{
  [XmlEnum(Name="未知")]
  Unknown,
  [XmlEnum(Name="移动")]
  Mobile,
  [XmlEnum(Name="固定")]
  Fixed,
  [XmlEnum(Name="小灵通")] //新加入
  PHS
  
  
}

  4.2 重新生成 xsd

  方法在上面说过了

  4.3 数据库更改

declare
 --旧Schema
 oldSchemaDocnvarchar2(2000):='<xs:schemaelementFormDefault="qualified"xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xs:elementname="Phones"nillable="true"type="ArrayOfPhone"/>
 <xs:complexTypename="ArrayOfPhone">
  <xs:sequence>
   <xs:elementminOccurs="0"maxOccurs="unbounded"name="Phone"nillable="true"type="Phone"/>
  </xs:sequence>
 </xs:complexType>
 <xs:complexTypename="Phone">
  <xs:sequence>
   <xs:elementminOccurs="0"maxOccurs="1"name="Code"type="xs:string"/>
   <xs:elementminOccurs="1"maxOccurs="1"name="Type"type="PhoneType"/>
  </xs:sequence>
 </xs:complexType>
 <xs:simpleTypename="PhoneType">
  <xs:restrictionbase="xs:string">
   <xs:enumerationvalue="未知"/>
   <xs:enumerationvalue="移动"/>
   <xs:enumerationvalue="固定"/>
  </xs:restriction>
 </xs:simpleType>
</xs:schema>';
--新Schema
 newSchemaDocnvarchar2(2000):='<xs:schemaelementFormDefault="qualified"xmlns:xs="http://www.w3.org/2001/XMLSchema">
 <xs:elementname="Phones"nillable="true"type="ArrayOfPhone"/>
 <xs:complexTypename="ArrayOfPhone">
  <xs:sequence>
   <xs:elementminOccurs="0"maxOccurs="unbounded"name="Phone"nillable="true"type="Phone"/>
  </xs:sequence>
 </xs:complexType>
 <xs:complexTypename="Phone">
  <xs:sequence>
   <xs:elementminOccurs="0"maxOccurs="1"name="Code"type="xs:string"/>
   <xs:elementminOccurs="1"maxOccurs="1"name="Type"type="PhoneType"/>
   <xs:elementminOccurs="0"maxOccurs="1"name="Make"type="xs:string"/>
  </xs:sequence>
 </xs:complexType>
 <xs:simpleTypename="PhoneType">
  <xs:restrictionbase="xs:string">
   <xs:enumerationvalue="未知"/>
   <xs:enumerationvalue="移动"/>
   <xs:enumerationvalue="固定"/>
   <xs:enumerationvalue="小灵通"/>
  </xs:restriction>
 </xs:simpleType>
</xs:schema>';

--变量存储xmldiffxml差异结果

 

diffXMLDocclob;

 

--url

 

v_schema_urlnvarchar2(255):= 'http://www.OracleDemo.com/Phones.xsd';

 

begin

 

 --生成差异结果

 

 selectxmldiff(xmltype(oldSchemaDoc),xmltype(newSchemaDoc)).getClobVal()intodiffXMLDocfromdual;

 

 --11g新增加的原地更改函数,性能比原来那个DBMS_XMLSCHEMA.copyEvolve

 

 --概念执行原地XML模式演变http://www.oracle.com/technology/global/cn/obe/11gr1_db/datamgmt/xmldb2_a/xmldb2_a.htm

 

 DBMS_XMLSCHEMA.inPlaceEvolve(v_schema_url, xmltype(diffXMLDoc));

 

end;

 

  流程就是拿 旧的Schema 和 新的Schema 比较生成一个差异结果 select xmldiff...这里,然后调用 DBMS_XMLSCHEMA.inPlaceEvolve

  更新 Schema很简单函数就用到两个,代码没多少就是2个Schema 占地方;

  4.4 在插入一条数据看看

  ---在插入一条

INSERTINTOXML_USER_INFOVALUES(3,'用户3'
  ,XMLType('<Phonesxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <Phone>
  <Code>13930588003</Code>
  <Type>移动</Type>  
 </Phone>
 <Phone>
  <Code>024-32222223-1</Code>
  <Type>固定</Type>
  <Make>公司</Make>
 </Phone>
 <Phone>
  <Code>024-3788883</Code>
  <Type>小灵通</Type>
  <Make>公司</Make>
 </Phone>
</Phones>'
  )
)
/

 

  4.5 本步骤总结

  更改还是比较方便的;数据库更改在所难免可以快速的更改才是王道;不过例子比较片面,大待大规模测试

  五、用 C# 写一个网页,显示这些数据;

  5.1 显示效果

  显示效果如下(砢碜点啊)

  

  NPK

  用户名

  电话信息

  1

  用户1

  【13940588000;移动;】、【024-22222222-1;固定;】、【12345678;未知;】

  2

  用户2

  【13920588002;移动;】、【024-22222222-1;固定;】、【2788882;未知;】

  3

  用户3

  【024-32222223-1;固定;公司】、【024-3788883;小灵通;公司】、【13930588003;移动;】

  4

  用户4

  【13940588004;移动;个人】、【024-42222224-1;固定;公司】、【024-4788884;小灵通;公司】、【024-4788844;固定;个人】

  5

  用户5

  【13950588005;移动;个人】、【024-52222225-1;固定;公司】、【024-5788885;小灵通;公司】、【024-5788845;固定;个人】

 

  5.2 代码

  //用户信息(XML_USER_INFO 是一样的)

publicclassUserInfo
  {
    int_NPK;
    publicintNPK
    {
      get{return_NPK;}
      set{_NPK=value;}
    }
    string_userName;
    publicstringUserName
    {
      get{return_userName;}
      set{_userName=value;}
    }
    
    Phones_phones;
    publicPhonesPhones
    {
      get{return_phones;}
      set{_phones=value;}
    }
  }

  //数据操作代码 (很简单就是,把数据全差出来)

publicclassUserInfoDAL
{
  publicstaticList<UserInfo>GetUserInfos()
  {
    //我本身是想用ODP.net不过为了让大家看懂就先用ms的OracleClient
    //其实 ODP.net操作oracle更方便点;直接支持xmlType的不用转换
    
    //GETSTRINGVAL是OraclexmlType类的一个函数,以string形式返回xml对象数据
    conststringSQL="SELECTt.NPK,t.USER_NAME,t.PHONES.GETSTRINGVAL()as PHONESFROMXML_USER_INFOtorderby1";
    List<UserInfo>models=newList<UserInfo>();
    stringconnstring=System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
    
    using(OracleConnectionconn=newOracleConnection(connstring))
    {
      conn.Open();
      using(OracleCommandcmd=newOracleCommand(SQL,conn))
      {
        
        using(OracleDataReaderreader=cmd.ExecuteReader())
        {
          while(reader.Read())
          {
            DataTabledt=reader.GetSchemaTable();
            
            intnpk=Convert.ToInt32(reader["NPK"]);
            
            stringuserName=reader["USER_NAME"].ToString();
            
            //读取XML类型
            stringphonesXml=reader["PHONES"].ToString();
            
            //这里是我自己扩展的全局的string对象的方法,就是把string通过XML反序列化为对象实例
            Phonesps=phonesXml.XMLToObject<Phones>();  
            
            models.Add(newUserInfo(){NPK=npk,UserName=userName,Phones=ps});
          }
        }
      }
    }
    returnmodels;
  }
}

  //网页的代码

<asp:GridViewID="GridView1"runat="server"AutoGenerateColumns="False"DataSourceID="ObjectDataSource1">
  <Columns>
    <asp:BoundFieldDataField="NPK"HeaderText="NPK"SortExpression="NPK"/>
    <asp:BoundFieldDataField="UserName"HeaderText="用户名"SortExpression="UserName"/>
    <asp:BoundFieldDataField="Phones"HeaderText="电话信息"SortExpression="Phones"/>
  </Columns>
</asp:GridView>
<asp:ObjectDataSourceID="ObjectDataSource1"runat="server"
  SelectMethod="GetUserInfos"TypeName="WebApplication1.UserInfoDAL">
</asp:ObjectDataSource>

 

  --可能有人会问;你的网页【电话信息】那列怎么显示成那个样子的?

  --其实很简单;重写 Phones 类的 ToString() 想怎么显示都可以的,我这里就不贴代码了

  --如果有人需要说一声,因为不属于本片博文的技术讨论范围就不贴上了;

  5.3 本步骤总结

  读取操作也是很方便的,比如在做分页的时候,就比连接2个表(用户表、电话表)要方便的多

  而且返回数据,可以直接转换为对象更加方便了;不过数据量大的子表就不太适合了这种方式

  6、总结

  目前看来

  XMLType比起平面表更加类似 class 类

  因为.net 可以直接通过类生成Schema在生成 XMLType 数据库表,能节省一些数据表的设计时间,改完对象直接更改数据库就可以了

  遗憾:C# 视乎生成不了Schema的很多约束属性如限制字段长度的约束

  还有集合内的类型,加不了外键比如本来我要是把 电话类型放到一个平面表里

  就加不上外键了;

  处理那些树形的数据比较适合;

  如一个主记录、关联n个子记录的情况

  查询插入都是比较方便的,直接可以序列化或反序列化为对象或xml 能节省些代码;

  遗憾:XML 序列化可能慢点,不过可以使操作更明晰,如果直接操作 xml 的话太头痛了代码也乱

  终于写完了,贴了这么多代码,园子里用Oracle 的不多,可能有人看不懂,不过问我就好了

  我可以解答你,大家共同学习进步吧!

  不过本人公司基本都是玩 oracle 没有时间去玩 sqlserver 抱歉了先

  如果有时间在做个 sqlserver 的例子吧!

  或者出一个 sqlserver 和 oracle 的 xml 类型对比性测试,如果有人愿意和我做这次试验,我可以提供 oracle 的测试机和代码

我对sqlserver 不是很熟悉的,已经n年没用了,如果我自己出对比测试,怕糟蹋了 sqlserver

  我家的计算机是 AMD6000 +、4G内存

  这种测试应该是没啥问题的,跑些不是超级大的应用还是可以的;

 



相关教程