2012-03-23 30 views
4

私は、タイプを返すOracleパッケージ内の関数を試して呼び出すためにC#を使用しています。C#からタイプを返すOracle関数を呼び出す

は、私がこれまでのところ、私は全体来てアドバイスがあり、これを研究日の最後のカップルを費やしてきた:

  • はodp.net 11gのデータアクセスドライバを使用します。
  • パラメータ出力方向をパラメータ出力を確保
  • を戻り値に設定されていることを確認最初のパラメータは
  • は、出力パラメータをOracle型 名でudttypenameを付け加えます。以下は

(いくつかの似たようなケースはこれで解決された彼女に尋ねた)このudttypenameが大文字であることを確認する

  • は、(パッケージは環境設定と呼ばれている)Oracleパッケージです:

    以下
    Type P_Details Is Record(
        var1 a.a_Type_Key%Type 
        ,var2 Varchar2(1) 
        ,var3 a.b%Type 
        ,var4 c.Type_Key%Type 
        ,var5 d.Code%Type 
        ,var6 d.Product_Path%Type 
        ,var7 a.Channel_Key%Type 
        ,var8 a.From_Date%Type 
        ,var9 a.To_Date%Type); 
    
    Type P_List Is Table Details; 
    
    Function Get(p_1 In  Number, 
          p_2 In  Varchar2, 
          p_3 In  Varchar2, 
          p_4 In  Date, 
          p_5 In Out Varchar2) Return List; 
    

    Oracleパッケージを呼び出すために使用されるC#コードです。

    using (var connection = new OracleConnection(ConnectionString)) 
    { 
        using (var command = new OracleCommand 
              { 
               CommandType = CommandType.StoredProcedure, 
               CommandText = "PACKAGENAME.FUNCTIONNAME", 
               Connection = connection, 
               BindByName = true 
              }) 
        { 
         var output = new OracleParameter 
             { 
              UdtTypeName = "PREFS.PREFERENCE_LIST", 
              ParameterName = "p_details", 
              OracleDbType = OracleDbType.Object, 
              Direction = ParameterDirection.ReturnValue 
             }; 
         command.Parameters.Add(output); 
         command.Parameters.Add(new OracleParameter 
                { 
                 ParameterName = "p_1", 
                 OracleDbType = OracleDbType.Decimal, 
                 Direction = ParameterDirection.Input, 
                 Value = details.RuleId 
                }); 
         command.Parameters.Add(new OracleParameter 
                { 
                 ParameterName = "p_2", 
                 OracleDbType = OracleDbType.Decimal, 
                 Direction = ParameterDirection.Input, 
                 Value = details.CustomerDetails.CtiId 
                }); 
         command.Parameters.Add(new OracleParameter 
                { 
                 ParameterName = "p_3", 
                 OracleDbType = OracleDbType.Varchar2, 
                 Direction = ParameterDirection.Input, 
                 Value = details.CustomerDetails.Surname 
                }); 
         command.Parameters.Add(new OracleParameter 
                { 
                 ParameterName = "p_4", 
                 OracleDbType = OracleDbType.Varchar2, 
                 Direction = ParameterDirection.Input, 
                 Value = details.CustomerDetails.Postcode 
                }); 
         command.Parameters.Add(new OracleParameter 
                { 
                 ParameterName = "p_5", 
                 OracleDbType = OracleDbType.Date, 
                 Direction = ParameterDirection.Input, 
                 Value = details.CustomerDetails.DateOfBirth 
                }); 
         command.Parameters.Add(new OracleParameter 
                { 
                 ParameterName = "p_6", 
                 OracleDbType = OracleDbType.Varchar2, 
                 Direction = ParameterDirection.InputOutput 
                }); 
         connection.Open(); 
         command.ExecuteNonQuery(); 
        } 
    } 
    

    私は今、エラーを取得しています

    "OCI-22303:タイプ "

    PACKAGENAME.TYPENAMEが、私は次の形式を試してみたUDTTYPENAMEについては

    " が見つかりません"

    • TYPENAME
    • FUNCTIONNAME.TYPENA ME
    • PACKAGENAME.TYPENAME
    • PACKAGENAME.TYPENAME
    • PACKAGENAME.FUNCTIONNAME.TYPENAME
    • 私は今てきたように、私はこのために任意のヘルプや応答をいただければと思います

    SCHEMA.PACKAGENAME.TYPENAMEアイデアがなくなります

  • 答えて

    3
    あなたが実際にこの小さな自動化して、すべてのルーチン(プロシージャー、関数など)ともREFカーソル型のパラメータのための鋳造と準備パラメータを簡素化することができます

    a)は共通で次の型とルーチンを定義しますパッケージ(utilsと呼ぶことができます)。

    あなたは)

    public void SetupParams(string RoutineName, OracleCommand cmd, IDictionary<string, string> prms, bool keepConnectionOpen = true) 
          { 
          Debug.WriteLine("Setting parameters for " + RoutineName); 
          if (cmd != null) cmd.Parameters.Clear(); 
          string pname = ""; 
          string[] s = RoutineName.Split('.'); 
          DataTable tblParams = Select(String.Format("Select * from Table(pkgUtils.ftRoutineSchema('{0}','{1}')) ", s[0], s[1])); 
          cmd.CommandText=RoutineName; 
          foreach (DataRow dr in tblParams.Rows) 
           { 
           using (OracleParameter p = new OracleParameter()) 
            { 
            pname = dr["COLUMnNAME"].ToString() == "" ? "returnvalue" : pname = dr["COLUMnNAME"].ToString().ToLower(); 
            if (prms.Keys.Contains(pname)) p.Value = prms[pname]; 
            string direction = dr["Direction"].ToString().ToLower(); 
            string sptype = (string)dr["DataType"]; 
            string[] sx = dr["DataType"].ToString().Split(new char[] { '(', ',', ')' }); 
            direction = pname == "returnvalue" ? "rc" : direction; 
            p.ParameterName = pname; 
            #region case type switch 
            switch (sx[0].ToLower()) 
             { 
             case "number": 
              // p.DbType = OracleDbType.Decimal; 
              p.OracleDbType = OracleDbType.Decimal; 
              break; 
    
             case "varchar2": 
              p.DbType = DbType.String; 
              p.Size = 65536; 
              // p.Size = prms[pname].Length; 
              // p.Size = int.Parse(sx[1]); 
              break; 
             case "ref cursor": 
              p.OracleDbType = OracleDbType.RefCursor; 
              // direction = "rc"; // force return value 
    
              break; 
             case "datetime": 
              p.DbType = DbType.DateTime; 
              break; 
             case "ntext": 
             case "text": 
              p.DbType = DbType.String; 
              p.Size = 65536; 
              break; 
             default: 
              break; 
             } 
            //------------------------------------------------------------------------------- 
            switch (direction) 
             { 
             case "in": p.Direction = ParameterDirection.Input; break; 
             case "out": p.Direction = ParameterDirection.Output; break; 
             case "in/out": p.Direction = ParameterDirection.InputOutput; break; 
             case "rc": p.Direction = ParameterDirection.ReturnValue; break; 
             default: break; 
             } 
    
            #endregion 
            cmd.Parameters.Add(p); ; 
            } 
           } 
          } 
    

    Cを呼び出している

    Type recRoutineSchema is Record (ColumnName varchar2(64),DataType Varchar2(20), ColumnOrder number, Direction varchar2(10), sSize nUMBER); 
    
    Type tblRoutineSchema is table of recRoutineSchema; 
    
        function ftRoutineSchema(pkg varchar2,Routine varchar2) return tblRoutineSchema PIPELINED is 
         x recRoutineSchema; 
         pkN varchar2(100); 
        rtN varchar2(100); 
        Begin 
        FOR Y in (Select Argument_Name ColumnName 
             ,Data_type  DataType 
             ,Position  ColumnOrder 
             ,In_out   Direction 
             ,Data_length SSize 
            from user_ARGUMENTS 
             where package_Name=Upper(pkg) 
             and object_name=Upper(Routine) order by position 
             ) 
        LOOP 
         PIPE ROW(Y); 
        END LOOP; 
        Return; 
        End; 
    

    b)、および取得するために、機能の上に呼び出すC#の方法と手続き/機能の設定パラメータ。次のように任意の関数/ procを簡単に呼び出すことができます。このプロシージャは実際に2つのrefcursorパラメータを返し、データセットをポップします。

    private void btnDumpExcel_Click(object sender, EventArgs e) 
         { 
         IDictionary<string, string> p = new Dictionary<string, string>(); 
    
         p.Add("pcomno", "020"); 
         p.Add("pcpls", "221"); 
         p.Add("pUploaderName", "Anthony Peiris"); 
         try 
          { 
          pGroupDs = O.execProc2DatSet("priceWorx.prSnapshotDiscounts", p, false, false); 
          Excel.MakeWorkBook(ref pGroupDs, ref O, "1"); 
    
          } 
         catch (Exception ex) 
          { 
          Debug.WriteLine(ex); 
          Debugger.Break(); 
          } 
         //Excel.MakeWorkBook(ref ds, ref O, "1"); 
    
         } 
    

    ここではOです。execProc2DataSet

    public DataSet execProc2DatSet(string storedProcedureName, IDictionary<string, string> prms, bool propagateDbInfo, bool leaveConnectionOpen = false) 
          { 
          // initPackage(storedProcedureName.Substring(0,storedProcedureName.IndexOf('.'))); 
          try 
           { 
           using (OracleCommand cmd = new OracleCommand("", conn)) 
            { 
            cmd.CommandType = CommandType.StoredProcedure; 
            cmd.CommandText = storedProcedureName; 
            //dep = new OracleDependency(cmd); 
            //dep.OnChange += new OnChangeEventHandler(dep_OnChange); 
            if (prms != null) SetupParams(storedProcedureName, cmd, prms, true); 
            using (OracleDataAdapter da = new OracleDataAdapter(cmd)) 
             { 
             if (conn.State != ConnectionState.Open) 
              { 
              conn.Open(); 
              cmd.Connection = conn; 
              } 
             using (DataSet ds = new DataSet()) 
              { 
              da.Fill(ds); 
              return ds; 
              } 
             } 
            } 
           } 
          catch (Exception ex) 
           { 
           Debug.WriteLine(ex); 
           Debugger.Break(); 
           return null; 
           } 
          finally 
           { 
           if (!leaveConnectionOpen) conn.Close(); 
           } 
          } 
    

    このアプローチでは、パラメータ設定は今、完全に自動化されているのでパラメータは、最後以降に変更されたかもしれないものについてconcerendすることなく、あなたのProce /関数のパラメータを変更することができます。 HTH

    +2

    残念ながら、Oracle側は私が何も制御できないブラックボックスのほうが多いです。私はOracleパッケージの所有者に上記を提案することができますが、最初にすべてのルートを探索したいと考えました。 – AndyS

    関連する問題