在.Net中使用Oracle的表类型和对象类型

原创 2013年09月10日 14:22:41

在一般的数据存取操作过程中,如果要对一个主表和对应的子表进行插入操作,那么我们最常见的写法就是写两个存储过程或者SQL语句,一个负责主表数据插入,一个负责子表数据插入,然后在一个事务中实现主表和子表数据的插入。

现在遇到一个问题是,能否在一个存储过程中实现主表和子表数据的插入呢?那么就需要将一对多的数据作为存储过程的参数传入。这种情况下就需要使用表类型。下面以一个学生和班级的例子来说明:

先建立一个班级表和一个学生表,一个班级里面有多个学生。


代码
CREATE TABLE CLASS
(
   CLASSID     
NUMBER (38PRIMARY KEY,
   CLASSNAME   
VARCHAR2 (50 BYTE) NOT NULL
);

CREATE TABLE STUDENT
(
  STUID        
NUMBER(38PRIMARY KEY,
  CLASSID      
NUMBER(38)                       NOT NULL,
  STUNAME      NVARCHAR2(
50)                    NOT NULL,
  STUGENDER    
CHAR(1 BYTE),
  STUBIRTHDAY  DATE,
  DESCRIPTION  NVARCHAR2(
2000)
);

CREATE SEQUENCE CLASSID;

CREATE SEQUENCE STUDENTID;

首先我们需要在Oracle中创建一个学生的对象类型,这个对象类型中就是学生的属性:

CREATE OR REPLACE type StudentType as object
(
       StuName nvarchar2(
50),
       StuGender 
char(1),
       StuBirthday date,
       StuDescription nvarchar2(
2000)
);

 

接下来是将这个学生类型创建成表类型:

CREATE OR REPLACE type StuList as table of StudentType;

接下来就是写我们的一个插入存储过程,将班级和学生列表作为参数传入,具体脚本为:


代码
CREATE OR REPLACE PROCEDURE ZY.AddClassStudent(

ClassName 
in varchar2,
Students 
in StuList
IS

BEGIN
   
insert into Class values(classid.nextval,ClassName);
   
insert into Student(StuID,ClassID,StuName,Stugender,Stubirthday,Description)
   
select studentid.nextval,classid.currval,StuName,StuGender,StuBirthday,studescription
   
from TABLE(Students);
   EXCEPTION
     
WHEN NO_DATA_FOUND THEN
       
NULL;
     
WHEN OTHERS THEN
       RAISE;
END AddClassStudent;

现在Oracle服务器上的各个对象已经创建完成,接下来就是要编写C#代码,连接到Oracle数据库,插入数据了。

在C#项目中添加Oracle.DataAccess的引用,这是Oracle为.Net开发的类库,可以从官网下载。添加引用后,再添加命名空间:

using Oracle.DataAccess.Types;
using Oracle.DataAccess.Client;

 

然后再创建Student对应的类:


代码
public class Student : IOracleCustomType
    {
        
#region IOracleCustomType Members

        
public void FromCustomObject(Oracle.DataAccess.Client.OracleConnection con, IntPtr pUdt)
        {
            
if (StudentName != null)
                OracleUdt.SetValue(con, pUdt, 
"STUNAME", StudentName);
            
else
                
throw new NullReferenceException("STUNAME is null");
            OracleUdt.SetValue(con, pUdt, 
"STUGENDER", Gender);
            OracleUdt.SetValue(con, pUdt, 
"STUBIRTHDAY", Birthday);
            OracleUdt.SetValue(con, pUdt, 
"STUDESCRIPTION", Description);
        }

        
public void ToCustomObject(Oracle.DataAccess.Client.OracleConnection con, IntPtr pUdt)
        {
            StudentName 
= (String)OracleUdt.GetValue(con, pUdt, "STUNAME");
            Gender 
= (String)OracleUdt.GetValue(con, pUdt, "STUGENDER");
            Birthday 
= (DateTime)OracleUdt.GetValue(con, pUdt, "STUBIRTHDAY");
            Description 
= (String)OracleUdt.GetValue(con, pUdt, "STUDESCRIPTION");
        }

        
#endregion

        [OracleObjectMappingAttribute(
"STUNAME")]
        
public String StudentName { getset; }

        [OracleObjectMapping(
"STUGENDER")]
        
public string Gender { getset; }

        [OracleObjectMapping(
"STUBIRTHDAY")]
        
public DateTime Birthday { getset; }

        [OracleObjectMapping(
"STUDESCRIPTION")]
        
public string Description { getset; }

    }

并添加Student类对应Oracle对象类型的映射,通过Attribute来指定:


代码
[OracleCustomTypeMappingAttribute("STUDENTTYPE")]
public class StudentFactory : IOracleCustomTypeFactory
{
    
#region IOracleCustomTypeFactory Members

    
public IOracleCustomType CreateObject()
    {
        
return new Student();
    }

    
#endregion
}

现在StudentType类型已经创建完成,接下来就是创建StuList类型对应的类:


代码
[OracleCustomTypeMappingAttribute("STULIST")]
public class StudentList_TabFactory : IOracleArrayTypeFactory
{
    
#region IOracleArrayTypeFactory Members

    
public Array CreateArray(int numElems)
    {
        
return new Student[numElems];
    }

    
public Array CreateStatusArray(int numElems)
    {
        
return null;
    }

    
#endregion
}

这里可以看到,返回的是Student的数组。现在准备工作都已经完成,接下来就是初始化一点数据,然后调用存储过程了,代码如下:


代码
Student s1 = new Student() { StudentName = "张三", Birthday = Convert.ToDateTime("1984/12/29"), Gender = "M", Description = "HAHA。" };
           Student s2 
= new Student() { StudentName = "李四", Birthday = Convert.ToDateTime("1982/12/29"), Gender = "F", Description = "A。" };
           Student s3 
= new Student() { StudentName = "王五", Birthday = Convert.ToDateTime("1982/1/29"), Gender = "M", Description = "B。" };
           Student s4 
= new Student() { StudentName = "小月月", Birthday = Convert.ToDateTime("1985/10/11"), Gender = "F", Description = "C。" };
           List
<Student> ss1 = new List<Student>();
           ss1.Add(s1);
           ss1.Add(s2);
           ss1.Add(s3);
           ss1.Add(s4);

           
string conn = "Data Source=BRDWDEV;User Id=zy;Password=123;";
           
using (OracleConnection oc = new OracleConnection(conn))
           {
               oc.Open();

               OracleCommand cmd 
= oc.CreateCommand();
               cmd.CommandType 
= System.Data.CommandType.StoredProcedure;

               cmd.CommandText 
= "ZY.ADDCLASSSTUDENT";

               OracleParameter p0 
= new OracleParameter();
               p0.OracleDbType 
= OracleDbType.Varchar2;
               p0.UdtTypeName 
= "CLASSNAME";
               p0.Value 
= "测试班级名";
               p0.Direction 
= ParameterDirection.Input;
               cmd.Parameters.Add(p0);

               OracleParameter p1 
= new OracleParameter();
               p1.OracleDbType 
= OracleDbType.Array;
               p1.Direction 
= ParameterDirection.Input;
               p1.UdtTypeName 
= "STULIST";//注意这里是类型,而不是参数名
               p1.Value = ss1.ToArray();//注意这里应该是数组
               cmd.Parameters.Add(p1);

               
int count = cmd.ExecuteNonQuery();
               Console.WriteLine(count);
               oc.Close();
           }

以此类推,其实还可以把班级建立对象类型,然后再建立班级列表类型,这样就可在一个存储过程中插入多个班级,每个班级多个学生的数据。

版权声明:本文为博主原创文章,未经博主允许不得转载。

Oracle中Clob类型处理解析

   最近利用NHibernate映射类型为Clob字段在插入数据时发现当字符的字节数(一个半角字符一个字节,一个全角字符两个字节)在2000-4000之间时报错(ORA-01461:仅可以插入LON...
  • pojianbing
  • pojianbing
  • 2008年08月09日 08:52
  • 28021

Oracle中表的几种类型

表的功能:存储、管理数据的基本单元(二维表:有行和列组成) 2、表的类型: 1)堆表:heap table :数据存储时,行是无序的,对它的访问采用全表扫描。 2)分区表 表>2G ...
  • S630730701
  • S630730701
  • 2016年08月04日 20:17
  • 3018

oracle中char与varchar2的区别

oracle中char与varchar2的区别      1. CHAR的长度是固定的,而VARCHAR2的长度是可以变化的,比如,存储字符串“abc",对于CHAR(20),表示你...
  • haiross
  • haiross
  • 2015年03月09日 09:44
  • 5087

oracle中number和varchar2的自动转换的情况

(转) 今天测试分区索引,发现oracle智能化的一方面:若列为number类型,用其作为where条件时,变量为varchar2类型时会自动将变量转换为number类型,而不是将列转换为numbe...
  • syx19930206
  • syx19930206
  • 2014年03月10日 12:00
  • 2295

oracle表空间类型

表空间可以按4种方式分类 一、按数据文件的类型,分为: 大文件表空间(bigfile tablespace)此为10g新增功能 小文件表空间(smallfile tablespace)此为创建时...
  • lu8000
  • lu8000
  • 2013年05月24日 16:50
  • 1737

Oracle-33-变量%type、变量%rowtype、记录类型、记录表类型

一、%type变量 当用户事先并不知道检索的数据列的数据类型,可以使用%type定义变量。 比如:SQL>idemp.empno%type就是将emp表中empno列的数据类型为变量id的数据类型。 ...
  • wy_0928
  • wy_0928
  • 2016年04月15日 09:48
  • 2428

Oracle数据类型与.NET中的对应关系

转载自:http://blog.sina.com.cn/s/blog_3c6ecea90100nqry.html Oracle连接添加的引用不同,会存在数据类型不同以及其他一些差别,...
  • luxin10
  • luxin10
  • 2011年10月10日 18:59
  • 867

ORACLE 绑定变量用法总结

之前对Oracle中的变量一直没个太清楚的认识,比如说使用:、&、&&、DEIFINE、VARIABLE……等等。今天正好闲下来,上网搜了搜相关的文章,汇总了一下,贴在这里,方便学习。   ===...
  • SunWuKong_Hadoop
  • SunWuKong_Hadoop
  • 2016年12月20日 15:07
  • 437

Oracle建表常用数据类型详解

前言: 为列指定数据类型并不难,难的是指定合适的数据类型。同样是字符串类型,选择定长还是变长,其中大有文章。所以需要耐心而细致的学习下面的内容。 创建表时,必须为表的各个列指定数据类型。如果实...
  • congcongsuiyue
  • congcongsuiyue
  • 2014年11月14日 10:25
  • 1659

Oracle type (自定义类型的使用)

oracle - type   type定义: oracle中自定义数据类型 oracle中有基本的数据类型,如number,varchar2,date,numeric,float.....
  • u013490585
  • u013490585
  • 2014年11月21日 15:19
  • 1709
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在.Net中使用Oracle的表类型和对象类型
举报原因:
原因补充:

(最多只允许输入30个字)