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

简介:

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

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

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


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

CREATE   TABLE  STUDENT
(
  STUID        
NUMBER ( 38 PRIMARY   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 {  get set ; }

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

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

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

    }
复制代码

并添加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();
           }
复制代码

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

目录
相关文章
|
6月前
|
消息中间件 关系型数据库 Kafka
实时计算 Flink版产品使用合集之oracle cdc 抽取新增一张表 可以从savepoint恢复吗
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
3月前
|
存储 C#
揭秘C#.Net编程秘宝:结构体类型Struct,让你的数据结构秒变高效战斗机,编程界的新星就是你!
【8月更文挑战第4天】在C#编程中,结构体(`struct`)是一种整合多种数据类型的复合数据类型。与类不同,结构体是值类型,意味着数据被直接复制而非引用。这使其适合表示小型、固定的数据结构如点坐标。结构体默认私有成员且不可变,除非明确指定。通过`struct`关键字定义,可以包含字段、构造函数及方法。例如,定义一个表示二维点的结构体,并实现计算距离原点的方法。使用时如同普通类型,可通过实例化并调用其成员。设计时推荐保持结构体不可变以避免副作用,并注意装箱拆箱可能导致的性能影响。掌握结构体有助于构建高效的应用程序。
98 7
|
4月前
|
存储 Oracle 关系型数据库
|
3月前
|
分布式计算 Oracle 关系型数据库
实时计算 Flink版产品使用问题之获取Oracle的数据时无法获取clob类型的数据,该怎么办
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
4月前
|
SQL Oracle 关系型数据库
关系型数据库Oracle备份类型
【7月更文挑战第18天】
50 2
|
3月前
|
Oracle 关系型数据库
Navicat 连接Oracle ORA-28547: connection to server failed, probable Oracle Net admin error
Navicat 连接Oracle ORA-28547: connection to server failed, probable Oracle Net admin error
104 0
|
5月前
|
SQL Oracle 关系型数据库
实时计算 Flink版产品使用问题之oracle无主键的表支持同步吗如何实现
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
5月前
|
SQL 数据采集 Oracle
实时计算 Flink版产品使用问题之如何读取oracle中的blob类型的数据
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
5月前
|
运维 DataWorks Oracle
DataWorks产品使用合集之在标准模式下,当同步Oracle的表或视图时,是否需要在源端的测试和生产环境中都存在要同步的表或视图
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
45 3
|
4月前
|
开发框架 .NET API
.NET Core 和 .NET 标准类库项目类型有什么区别?
在 Visual Studio 中,可创建三种类库:.NET Framework、.NET Standard 和 .NET Core。.NET Standard 是规范,确保跨.NET实现的API一致性,适用于代码共享。.NET Framework 用于特定技术,如旧版支持。.NET Core 库允许访问更多API但限制兼容性。选择取决于兼容性和所需API:需要广泛兼容性时用.NET Standard,需要更多API时用.NET Core。.NET Standard 替代了 PCL,促进多平台共享代码。