2009-08-12 57 views
7

有人知道如何使用PL/SSQL和ODP.NET从C#实现Oracle Advance Queue吗? 我无法在C#或VB.NET中找到具体示例或资源。 理想情况下,我想了解一些如何使用简单类型(XMl/string)排队和出队消息的示例。Oracle Advanced Queuing with .Net

回答

14

我无法帮助您了解最佳做法,但我可以帮助您使用UDT队列。在处理队列之前,您需要将数据库中的自定义类型生成到C#项目中。假设你已经安装了Visual Studio和ODP.NET,你只需要通过服务器资源管理器连接到数据库,找到你的UDT,点击右键并选择“生成自定义类...”,这些类直接映射到你的UDT并被使用存储出队信息。

这里是你会用它来排队的消息的代码示例:

private void main(string[] args) 
{ 
    string _connstring = "Data Source=host/DB;User 
    Id=USER;Password=PASSWORD1;"; 

     OracleConnection _connObj = new OracleConnection(_connstring); 

     // Create a new queue object 
     OracleAQQueue _queueObj = new OracleAQQueue("UDT_NAME", _connObj); 

     _connObj.Open(); 

     OracleTransaction _txn = _connObj.BeginTransaction(); 

     // Set the payload type to your UDT 
     _queueObj.MessageType = OracleAQMessageType.Udt; 
     _queueObj.UdtTypeName = "UDT_NAME"; 

     // Create a new message object 
     OracleAQMessage _msg = new OracleAQMessage(); 

     // Create an instance of JobClass and pass it in as the payload for the 
     // message 
     UDT_CUSTOM_CLASS _custClass = new UDT_CUSTOM_CLASS(); 
     // Load up all of the properties of custClass 
     custClass.CustString = "Custom String"; 
     custClass.CustInt = 5; 

     _msg.Payload = custClass; 

     // Enqueue the message 
     _queueObj.EnqueueOptions.Visibility = OracleAQVisibilityMode.OnCommit; 
     _queueObj.Enqueue(_msg); 

     _txn.Commit(); 
     _queueObj.Dispose(); 
     _connObj.Close(); 
     _connObj.Dispose(); 
     _connObj = null; 
} 

这是一个类似的过程中退出:

private void main(string[] args) 
{ 
    string _connstring = "Data Source=host/DB;User 
    Id=USER;Password=PASSWORD1;"; 

    OracleConnection _connObj = new OracleConnection(_connstring); 

    // Create a new queue object 
    OracleAQQueue _queueObj = new OracleAQQueue("UDT_NAME", _connObj); 

    // Set the payload type to your UDT 
    _queueObj.MessageType = OracleAQMessageType.Udt; 
    _queueObj.UdtTypeName = "UDT_NAME"; 

    _connObj.Open(); 

    OracleTransaction _txn = _connObj.BeginTransaction(); 

    // Dequeue the message. 
    _queueObj.DequeueOptions.Visibility = OracleAQVisibilityMode.OnCommit; 
    _queueObj.DequeueOptions.Wait = 10; 
    OracleAQMessage _deqMsg = _queueObj.Dequeue(); 

    UDT_CUSTOM_CLASS data = (UDT_CUSTOM_CLASS)_deqMsg.Payload; 

    // At this point, you have the data and can do whatever you need to do with it 

    _txn.Commit(); 
    _queueObj.Dispose(); 
    _connObj.Close(); 
    _connObj.Dispose(); 
    _connObj = null; 

} 

这是一个“简单”的例子。 Ed Zehoo为Oracle Database 11g提供了Pro ODP.NET的大部分功能。这是一本很好的书,我强烈建议它帮助您更好地理解OPD.NET所有内容的来龙去脉。您可以在这里购买电子书:http://apress.com/book/view/9781430228202。如果您输入优惠券代码MACWORLDOC,您可以获得$ 21.00的电子书。该优惠只适用于带有密码保护的PDF格式的电子书。我希望这有帮助!

0

AQ通过DBMS_AQ [adm]具有plsql接口。您所需要的只是从您的环境和常见的AQ示例和设置中运行该软件包。当你从c#调用这些包时,我认为没有什么特别的。

+0

对不起,但我必须使用PL/SQL和存储过程已成为问题的一部分。问题在于,当消息出列时,许多选项可用,例如连接超时。此外,UDT被用作dequeue存储过程的参数 - 我不知道如何使用10G从.Net创建UDT。我正在寻找的是一些C#代码和最佳实践的例子(例如关闭数据库连接或让它打开???) – Geo 2009-08-13 15:10:52

+0

有没有人有这方面的例子?我也在寻找这个。 ;) – user171523 2010-04-05 12:36:05

3

我不知道确切的答案,这个问题,但这里是我们做的:

  • 首先需要监听的ESB(ESB是建立在AQ)每一个.NET应用程序必须使用他自己的本地Oracle数据库并从那里取消邮件。消息传播到本地队列。这解决了与保持数据库连接打开以接收消息相关的潜在可扩展性问题。
  • 其次,我们构建了我们自己的基本封装存储过程的AQ库。 - 随着Oracle已经最终发布ODAC 11.1.0.7.20(支持AQ的ODP.NET),这不再需要。我们使用Oracle类型作为DTO的种类来定义消息合约。
+0

第二个选项是我做出列的。有趣的是,他们已经通过ODP.NET在.NET中添加了适当的支持。 – RichardOD 2010-03-30 14:22:09

1

我有一个要求,我必须排队/出队UDT消息的队列。这篇文章真的很有帮助。它几乎包含所有内容,但缺少“Oracle自定义类型”的创建。我认为它值得在这里添加代码,以便解决方案是完整的。

入队/出队在甲骨文:

用户与角色“AQ_ADMINISTRATOR_ROLE”必须创建。在下面的示例中,“AQUSER”是使用该角色创建的。

PL Sql to EnQueue: 

DECLARE 
    queue_options  DBMS_AQ.ENQUEUE_OPTIONS_T; 
    message_properties DBMS_AQ.MESSAGE_PROPERTIES_T; 
    message_id   RAW(16); 
    my_message   AQUSER.USER_DEFINED_TYPE; 
BEGIN 
    my_message := AQUSER.USER_DEFINED_TYPE('XXX','YYY','ZZZ'); 
    DBMS_AQ.ENQUEUE(
     queue_name => 'AQUSER.QUEUE_NAME', 
     enqueue_options => queue_options, 
     message_properties => message_properties, 
     payload => my_message, 
     msgid => message_id); 
    COMMIT; 
END; 
/

PL SQL to DeQueue 

DECLARE 
    queue_options  DBMS_AQ.DEQUEUE_OPTIONS_T; 
    message_properties DBMS_AQ.MESSAGE_PROPERTIES_T; 
    message_id   RAW(2000); 
    my_message   AQUSER.USER_DEFINED_TYPE; 
BEGIN 
    DBMS_AQ.DEQUEUE(
     queue_name => 'AQUSER.QUEUE_NAME', 
     dequeue_options => queue_options, 
     message_properties => message_properties, 
     payload => my_message, 
     msgid => message_id); 
    COMMIT; 
END; 
/

------------------------------------------------------------------------------------------- 

To create a Oracle Custom Type, you can use the following code: 

    public class CustomMessageType : IOracleCustomType, INullable 
    { 

     [OracleObjectMappingAttribute("XXXXX")] 
     public string XXXXX { get; set; } 

     [OracleObjectMappingAttribute("YYYYY")] 
     public string YYYYY { get; set; } 

     [OracleObjectMappingAttribute("ZZZZZ")] 
     public string ZZZZZ { get; set; } 

     public void FromCustomObject(Oracle.DataAccess.Client.OracleConnection con, IntPtr pUdt) 
     { 
      if (!string.IsNullOrEmpty(XXXXX)) 
      { 
       OracleUdt.SetValue(con, pUdt, "XXXXX", XXXXX); 
      } 
      if (!string.IsNullOrEmpty(YYYYY)) 
      { 
       OracleUdt.SetValue(con, pUdt, "YYYYY", YYYYY); 
      } 
      if (!string.IsNullOrEmpty(ZZZZZ)) 
      { 
       OracleUdt.SetValue(con, pUdt, "ZZZZZ", ZZZZZ); 
      } 
     } 

     public void ToCustomObject(Oracle.DataAccess.Client.OracleConnection con, IntPtr pUdt) 
     { 
      XXXXX = (string)OracleUdt.GetValue(con, pUdt, "XXXXX"); 
      YYYYY = (string)OracleUdt.GetValue(con, pUdt, "YYYYY"); 
      ZZZZZ = (string)OracleUdt.GetValue(con, pUdt, "ZZZZZ"); 
     } 

     public bool IsNull { get; set; } 

    } 


    [OracleCustomTypeMappingAttribute("SCHEMA.CUSTOM_TYPE")] 
    public class QueueMessageTypeFactory : IOracleCustomTypeFactory 
    { 
     public IOracleCustomType CreateObject() 
     { 
      return new CustomMessageType(); 
     } 
    }