2009-08-12 3 views
7

Qualcuno sa come implementare Oracle Advance Queue da C# usando PL/SSQL e ODP.NET? Non riesco a trovare un singolo esempio o risorsa con esempi concreti in C# o VB.NET. Idealmente vorrei alcuni esempi su come accodare e decodificare i messaggi con tipi semplici (XMl/stringa).Oracle Advanced Queuing con .Net

risposta

14

Non posso aiutarti con le migliori pratiche, ma posso aiutarti con una coda UDT. Prima di gestire la coda, è necessario generare tipi personalizzati dal database nel progetto C#. Supponendo che Visual Studio e ODP.NET siano installati, è sufficiente connettersi al database tramite Server Explorer, individuare i tuoi UDT, fare clic con il tasto destro e scegliere "Genera classe personalizzata ..." Queste classi si mappano direttamente ai tuoi UDT e vengono utilizzate per memorizzare le informazioni dequeued.

Ecco un esempio del codice si usa per accodare un messaggio:

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; 
} 

E 'un processo simile per annullare l'accodamento:

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; 

} 

Questo è un esempio di "semplice". Ne ho ricavato la maggior parte da Pro ODP.NET per Oracle Database 11g di Ed Zehoo. È un libro eccellente e lo raccomando vivamente di aiutarti a comprendere meglio i dettagli di OPD.NET. È possibile acquistare l'eBook qui: http://apress.com/book/view/9781430228202. Se inserisci il codice coupon MACWORLDOC, puoi ottenere l'eBook a $ 21,00. Questa offerta è valida solo per l'eBook che viene fornito in un formato PDF protetto da password. Spero che aiuti!

0

AQ ha un'interfaccia plsql tramite DBMS_AQ [adm]. Tutto ciò di cui hai bisogno è eseguire i pacchetti dal tuo ambiente e esempi e configurazioni AQ comuni. Non penso che ci sia qualcosa di speciale quando chiami quei pacchetti da C#.

+0

Spiacente ma che devo usare PL/SQL e stored procedure è già parte della domanda. Il problema è che quando si eliminano i messaggi sono disponibili molte opzioni, ad es. il timeout della connessione. Anche gli UDT sono usati come parametri per il processo di archiviazione dei depositi - non so come creare UDT da .Net con 10G. Quello che sto cercando sono alcuni esempi di codice C# e best practice (ad esempio chiudere la connessione db o lasciarlo aperto ???) – Geo

+0

Qualcuno ha qualche esempio su questo? Sto anche cercando questo. ;) – user171523

3

Non conosco la risposta esatta a questo problema, ma qui è quello che abbiamo fatto:

  • Prima ogni applicazione .NET che hanno bisogno di ascoltare sulla ESB (ESB è costruita su AQ) deve usare il proprio DB Oracle locale e rimuove i messaggi da lì. I messaggi vengono propagati alle code locali. Questo risolve il potenziale problema di scalabilità legato al mantenimento di una connessione DB aperta per ricevere i messaggi.
  • In secondo luogo abbiamo creato la nostra libreria AQ che incapsula in modo semplice le stored procedure. - questo non è più necessario poiché Oracle ha finalmente rilasciato un ODAC 11.1.0.7.20 (con un ODP.NET che supporta AQ). Utilizziamo i tipi Oracle come DTO per definire i contratti dei messaggi.
+0

La seconda opzione è ciò che ho fatto per desinteggiare. È interessante notare che hanno aggiunto il supporto adeguato in .NET tramite ODP.NET. – RichardOD

1

ho avuto un requisito in cui ho dovuto accodare/messaggi UDT dequeue a una coda. Questo post è stato davvero utile. Ha quasi tutto ma manca la creazione di un "Oracle Custom Type". Ho pensato che valesse la pena aggiungere quel codice qui in modo che la soluzione fosse completa.

Per Enqueue/rimozione in Oracle:

utente con il ruolo "AQ_ADMINISTRATOR_ROLE" deve essere creato. Nell'esempio seguente, "AQUSER" viene creato con quel ruolo.

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(); 
     } 
    }