Hi,

I coded a simple access to routines written in Cach�, to perform updates of
datasets.
If you are interested, see the code below, or contact me directly.

I hope it will help.

Regards

JM

Cach� side: a "portal" class named CGDispatch:

Class BSC.CGDispatch Extends %RegisteredObject [ ProcedureBlock ]
{
(four methods are found: CGInsertCmd to insert a new object, CGUpdate,
CGDelete and CGExecuteCmd to execute stored procs)

ClassMethod CGExecuteCmd(cacheBSCClass, cmd, msgIn As %String(MAXLEN=65536),
Output msgOut As %String(MAXLEN=65536)) [ SqlProc ]
{
 s Z1=$ZH
 do
##class(UsrJournal.Log).FAppend("class="_cacheBSCClass_";cmd="_cmd_";msgIn="
_msgIn,"CG",9)
 s cacheError=""  //error code (format is code;description)
 s rets=""    // return multidimensional array that will be converted to a
string
 s sqlErrorCode=0  //SQL error to be returned
 s $zt="CGEC"
 //de-serialisation of arguments in a multidimensional in the form of
hashtable: args( mykey ) = myvalue
 s i=1
 s s1=$P(msgIn,$C(31),1)
 while (s1'="")
 {
  s args($P(s1,$C(28),1))=$P(s1,$C(28),2)
  s i=i+1
  s s1=$P(msgIn,$C(31),i)
 }
 //call of the method
 //be careful to call an existing method, but a catch prevents any crash
 s cacheError=$zobjclassmethod(cacheBSCClass,cmd,.args,.rets)
CGEC2
 s $zt=""

 //append error code and description in the return string
 i (cacheError="") s cacheError="0;"
 s errorCode=$P(cacheError,";",1), errorDesc=$P(cacheError,";",2)
 s
msgOut="ERROR_CODE"_$C(28)_errorCode_$C(31)_"ERROR_DESC"_$C(28)_errorDesc_$C
(31)

 //serialise return hashtable in a string
//note the separators to separe pairs and to to separe key and value
//this has to be interpreted by .NET
 s i=$O(rets(""))
 while (i'="")
 {
  s msgOut=msgOut_i_$C(28)_rets(i)_$C(31)
  s i=$O(rets(i))
 }
 if ($L(msgOut)>0) { s msgOut=$E(msgOut,1,$L(msgOut)-1) }

 if (errorCode<0) s sqlErrorCode=-460 // General error

 // Return of %SQLProcContext
 If ($g(%sqlcontext)'=$$$NULLOREF)
 {
     Set %sqlcontext.SQLCode=sqlErrorCode
     If (sqlErrorCode'=0)
     {
      // if an error occured, we also add it to the ODBC error message
(throw an informative exception in .NET)
      Set %msg=cacheError
     }
 do ##class(UsrJournal.Log).FAppend("fin:"_(($ZH-Z1)*1000)_",
msgOut="_msgOut,"CG",9)
 q
CGEC
  do ##class(UsrJournal.Log).Append("Trap CG
Command","cacheBSCClass,cmd,msgIn",8,"CG")
  s cacheError=^CGErrorDefs(-100)
  goto CGEC2
 }
}


The .NET side (full source including DataSet fill/update):

using System;
using System.Collections;
using System.Data;
using System.Data.Common;
using System.Data.Odbc;
using System.IO;

namespace MPL.Common.Business.DataConnection
{
 public class CommanderBSDAC
 {
   protected OdbcDataAdapter m_DataAdapter=null;
    protected OdbcCommand m_ExecuteCmd=null;
    protected const int MAX_BUFFER_SIZE=65536;
    protected OdbcConnection m_Conn=null;
    protected string m_ClsName;
    protected string m_SessionId="";

  #endregion
  #region Constructeur
  /// <summary>
  /// CommanderBSDAC constructor
  /// </summary>
  /// <param name="session">client side session ID (used to authenticate
access)</param>
  public CommanderBSDAC(string session)
  {
   m_SessionId=session;
   m_DataAdapter=new OdbcDataAdapter();
   Init();
  }
  #endregion
  #region Generic commands
  /// <summary>
  /// Call of stored procedure
  /// </summary>
  /// <param name="clsName">Cache classname containing the method to
call</param>
  /// <param name="cmd">method name</param>
  /// <param name="htParametersIn">hashtable containing the parameters (key
and value)</param>
  /// <param name="htParametersOut">returned hashtable</param>
  /// <param name="htKeyTypOut">hashtable containing same keys as in
htParametersOut with values containing the data type. this allows to
directly retrieve typed data</param>
  public void CGExecuteCmd(string clsName,string cmd,Hashtable
htParametersIn,
   out Hashtable htParametersOut,Hashtable htKeyTypOut)
  {
   //include current session
   htParametersIn["SESSIONID"]=m_SessionId;
   if (htKeyTypOut!=null)
   {
    htKeyTypOut["SESSIONID"]=typeof(string);
    htKeyTypOut["ERROR_CODE"]=typeof(long);
    htKeyTypOut["ERROR_DESC"]=typeof(string);
   }
   SetClsName(clsName);
   string s_in=ParamsFormatter.Serialize(htParametersIn);
   OdbcCommand execute_cmd=m_ExecuteCmd;
   execute_cmd.Parameters["clsName"].Value=clsName;
   execute_cmd.Parameters["cmd"].Value=cmd;
   execute_cmd.Parameters["msgIn"].Value=s_in;
   using(m_Conn)
   {
    m_Conn.Open();
    execute_cmd.ExecuteNonQuery();
    m_Conn.Close();
   }
   string s_out="";
   s_out=(string)execute_cmd.Parameters["msgOut"].Value;
   htParametersOut=ParamsFormatter.Unserialize(s_out,htKeyTypOut);
  }


  /// <summary>
  /// Update a Cache class with a DiffGram DataSet
  /// </summary>
  /// <param name="clsName">Nom de la classe Cach�. Ex: Mpl.Natures</param>
  /// <param name="ds">DataSet de changement</param>
  public void CGUpdateDs(string tblName,string clsName,DataSet ds)
  {
   SetClsName(clsName);
   using(m_Conn)
   {
    m_DataAdapter.Update(ds,tblName);
   }
  }


  /// <summary>
  /// Fill a DataSet using a query in Cach�
  /// </summary>
  /// <param name="qryName"></param>
  /// <param name="htParametersIn">Param�tres d'appel de la commande</param>
  /// <param name="ds"></param>
  public void CGFillDs(string tblName,string qryName,Hashtable
htParametersIn,DataSet ds)
  {
   string qry_params="";
   OdbcCommand cmd=new OdbcCommand();
   OdbcParameterCollection parameters=cmd.Parameters;

   if(htParametersIn!=null)
   {
    int n=htParametersIn.Count;
    string[] s_arr=new string[n];
    int i=0;
    foreach(string s_key in htParametersIn.Keys)
    {
     OdbcParameter
param=parameters.Add(s_key,OdbcType.Char,MAX_BUFFER_SIZE,s_key);
     param.Direction=ParameterDirection.Input;
     param.Value=(string)htParametersIn[s_key];
     s_arr[i++]="?";
    }
    qry_params=string.Join(",",s_arr);
   }
   else
   {
    qry_params="";
   }

   string qry="{CALL "+qryName+"("+qry_params+")}";

   OdbcDataAdapter da=new OdbcDataAdapter();
   cmd.Connection=new OdbcConnection("DSN=MPL");
   cmd.CommandText=qry;
   cmd.CommandType=CommandType.StoredProcedure;
   da.SelectCommand=cmd;
   using(cmd.Connection)
   {
    da.Fill(ds,tblName);
   }
  }

  #endregion
  #region Initialisation of connection and commands
  private void Init()
  {
   InitHandlers();
   InitCommands();
   InitConnection();
  }

  private void InitHandlers()
  {
            m_DataAdapter.RowUpdating+=new
OdbcRowUpdatingEventHandler(RowUpdatingEventHandler);
   m_DataAdapter.RowUpdated+=new
OdbcRowUpdatedEventHandler(RowUpdatedEventHandler);
  }

  private void InitConnection()
  {
   m_Conn=new OdbcConnection("DSN=MPL");
   m_DataAdapter.InsertCommand.Connection=m_Conn;
   m_DataAdapter.UpdateCommand.Connection=m_Conn;
   m_DataAdapter.DeleteCommand.Connection=m_Conn;
   m_ExecuteCmd.Connection=m_Conn;
  }

  private void SetClsName(string clsName)
  {
   m_ClsName=clsName;
  }

  private void InitCommands()
  {
   ////////////////////////////////////////////
   /// Init commande INSERT
   ////////////////////////////////////////////
   OdbcCommand cmd=new OdbcCommand();
   cmd.CommandType=CommandType.StoredProcedure;
   OdbcParameterCollection parameters=cmd.Parameters;
   parameters.Clear();
   OdbcParameter
p=parameters.Add("clsName",OdbcType.Char,MAX_BUFFER_SIZE,"clsName");
   p.Direction=ParameterDirection.Input;
   p=parameters.Add("msgIn",OdbcType.Char,MAX_BUFFER_SIZE,"msgIn");
   p.Direction=ParameterDirection.Input;
   p=parameters.Add("msgOut",OdbcType.Char,MAX_BUFFER_SIZE,"msgOut");
   p.Direction=ParameterDirection.Output;
   cmd.CommandText="{CALL BSC.CGDispatch_CGInsertCmd(?,?,?)}";
   cmd.CommandType=CommandType.StoredProcedure;
   m_DataAdapter.InsertCommand=cmd;

   ////////////////////////////////////////////
   /// Init commande UPDATE
   ////////////////////////////////////////////
   cmd=new OdbcCommand();
   parameters=cmd.Parameters;
   parameters.Clear();
   p=parameters.Add("clsName",OdbcType.Char,MAX_BUFFER_SIZE,"clsName");
   p.Direction=ParameterDirection.Input;
   p=parameters.Add("msgIn",OdbcType.Char,MAX_BUFFER_SIZE,"msgIn");
   p.Direction=ParameterDirection.Input;
   p=parameters.Add("msgOut",OdbcType.Char,MAX_BUFFER_SIZE,"msgOut");
   p.Direction=ParameterDirection.Output;
   cmd.CommandText="{CALL BSC.CGDispatch_CGUpdateCmd(?,?,?)}";
   cmd.CommandType=CommandType.StoredProcedure;
   m_DataAdapter.UpdateCommand=cmd;

   ////////////////////////////////////////////
   /// Init commande DELETE
   ////////////////////////////////////////////
   cmd=new OdbcCommand();
   parameters=cmd.Parameters;
   parameters.Clear();
   p=parameters.Add("clsName",OdbcType.Char,MAX_BUFFER_SIZE,"clsName");
   p.Direction=ParameterDirection.Input;
   p=parameters.Add("msgIn",OdbcType.Char,MAX_BUFFER_SIZE,"msgIn");
   p.Direction=ParameterDirection.Input;
   p=parameters.Add("msgOut",OdbcType.Char,MAX_BUFFER_SIZE,"msgOut");
   p.Direction=ParameterDirection.Output;
   cmd.CommandText="{CALL BSC.CGDispatch_CGDeleteCmd(?,?,?)}";
   cmd.CommandType=CommandType.StoredProcedure;
   m_DataAdapter.DeleteCommand=cmd;

   ////////////////////////////////////////////
   /// Init commande EXECUTECMD
   ////////////////////////////////////////////
   m_ExecuteCmd=new OdbcCommand();
   parameters=m_ExecuteCmd.Parameters;
   parameters.Clear();
   p=parameters.Add("clsName",OdbcType.Char,MAX_BUFFER_SIZE,"clsName");
   p.Direction=ParameterDirection.Input;
   p=parameters.Add("cmd",OdbcType.Char,MAX_BUFFER_SIZE,"cmd");
   p.Direction=ParameterDirection.Input;
   p=parameters.Add("msgIn",OdbcType.Char,MAX_BUFFER_SIZE,"msgIn");
   p.Direction=ParameterDirection.Input;
   p=parameters.Add("msgOut",OdbcType.Char,MAX_BUFFER_SIZE,"msgOut");
   p.Direction=ParameterDirection.Output;
   m_ExecuteCmd.CommandText="{CALL BSC.CGDispatch_CGExecuteCmd(?,?,?,?)}";
   m_ExecuteCmd.CommandType=CommandType.StoredProcedure;
  }
  #endregion
  #region DataSet update callbacks
  //transfer one Dataset row to the hastable
  private void RowUpdatingEventHandler(object sender,
OdbcRowUpdatingEventArgs e)
  {
   DataRow row=e.Row;
   Hashtable ht_parameters=new Hashtable();
   //inclut la session en cours
   ht_parameters["SESSIONID"]=m_SessionId;
   foreach(DataColumn dc in row.Table.Columns)
   {
    object obj=null;
    if(row.RowState==DataRowState.Deleted)
    {
     obj=row[dc,DataRowVersion.Original];
    }
    else
    {
     obj=row[dc];
    }
    string key=dc.ColumnName;
    ht_parameters[key]=obj;
   }

   // serialize
   string s=ParamsFormatter.Serialize(ht_parameters);
   OdbcCommand cmd=e.Command;
   cmd.Parameters["msgIn"].Value=s;
   cmd.Parameters["clsName"].Value=m_ClsName;
  }
  //transfer one hashtable to a DataSet row
  private void RowUpdatedEventHandler(object sender, OdbcRowUpdatedEventArgs
e)
  {
   // Q313540
   if(e.StatementType==StatementType.Insert)
   {
    e.Status=UpdateStatus.SkipCurrentRow;
   }

   /*
    * 1�) Initialize the parameters types table
   */
   Hashtable ht_key_typ=new Hashtable();
   DataRow row=e.Row;
   /*
    * Pour chaque colonne, copier le type de la colonne dans
    * le type de param�tre.
   */
   foreach(DataColumn dc in row.Table.Columns)
   {
    string key=dc.ColumnName;
    ht_key_typ[key]=dc.DataType;
   }
   ht_key_typ["ERROR_CODE"]=typeof(long);
   ht_key_typ["ERROR_DESC"]=typeof(string);
   ht_key_typ["SESSIONID"]=typeof(string);

   /*
    *  2�) D�s�rialiser msgOut.
    *  3�) Pour chaque colonne assigner la valeur trouv�e dans msgOut.
   */

   OdbcCommand cmd=e.Command;
   if(cmd.Parameters["msgOut"].Value!=null)
   {
    string s=(string)cmd.Parameters["msgOut"].Value;
    Hashtable ht_parameters=ParamsFormatter.Unserialize(s,ht_key_typ);

    foreach(DataColumn dc in row.Table.Columns)
    {
     string key=dc.ColumnName;
     if(ht_parameters.ContainsKey(key))
     {
      if(ht_parameters.ContainsKey(key))
      {
       row[key]=ht_parameters[key];
      }
      else
      {

row[key]=string.Format("CommanderBSDACError:RowUpdatedEventHandler:N/A Key
in ht_parameters='{0}'",key);
      }
     }
    }
   }
   if (e.Errors!=null) throw(e.Errors);
  }
  #endregion
 }
}




Reply via email to