​OceanBaseForOracle中调用存储过程报错。 返回

SqlSugar 沟通中
23 1204
该叫什么 tcc 发布于2023/11/7
悬赏:0 飞吻

OceanBaseForOracleTest中,调用存储过程报错:

image.png


测试代码如下:

            Console.WriteLine("");
            Console.WriteLine("#### MasterSlave Start ####");
            //OceanBase Oracle 模式用这个 DbType.OceanBaseForOracle
            //OceanBase MySql 模式用DbType.MySql不要用这个
            SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
            {
                ConnectionString = Config.ConnectionString,//Master Connection
                DbType = DbType.OceanBaseForOracle,//Oracle 模式用这个 ,如果是MySql 模式用DbType.MySql
                InitKeyType = InitKeyType.Attribute,
                IsAutoCloseConnection = true
            });
            db.Aop.OnLogExecuted = (s, p) =>
            {
                Console.WriteLine(db.Ado.Connection.ConnectionString);
            };

            Console.WriteLine("Master:");

            //带返回值的存储过程
            //create or replace PROCEDURE "Proc_Test_table_return"(
            //p_col1 in VARCHAR2,
            //        p_xx1 out sys_refcursor,
            //        p_xx2 out sys_refcursor
            //) IS
            //BEGIN

            //    --Enter your procedure code
            //    open p_xx1 FOR

            //    select* from orders;

            //            open p_xx2 FOR

            //    select* from orders;
            //END;
            var p = new SugarParameter("@p_col1", "");
            var p1 = new SugarParameter("@p_xx1", ""); 
            p1.IsRefCursor = true;// 游标
            var p2 = new SugarParameter("@p_xx2", ""); 
            p2.IsRefCursor = true;// 游标

            var dt1 = db.Ado.UseStoredProcedure().GetDataTable("Proc_Test_table_return", p, p1, p2);
            var ret1 = p1.Value;
            var ret2 = p2.Value;


热忱回答23

  • tcc tcc VIP0
    2023/11/7

    另外,在这边的参数替换时好像没有起到作用,sql本身就只有一个存储过程名称。

    image.png

    0 回复
  • fate sta fate sta VIP0
    2023/11/7

    你可以试试SQL方式,ODBC应该不能用 UseStoredProcedure

    0 回复
  • tcc tcc VIP0
    2023/11/7

    @fate sta:SQL方式,具体怎么写?

    0 回复
  • fate sta fate sta VIP0
    2023/11/7

    数据库工具里面怎么调用存储过程就怎么写

    0 回复
  • tcc tcc VIP0
    2023/11/8

    @fate sta:试了,简单的存储过程是可以调用的,但是现在如果用游标返回结果集是做不到的,ODBC.dll里报错了,你这边有什么好的建议么?

    0 回复
  • fate sta fate sta VIP0
    2023/11/8

    @tcc: odbc 驱动好像没游标参数,你可以用ODBC原生ADO.NET试着写一个例子看看

    0 回复
  • tcc tcc VIP0
    2023/11/8

    此贴仅做记录,还是希望SqlSugar能支持OceanBaseForOracle调用存储过程返回结果集。


    存储过程如下:

    create or replace PROCEDURE "PROC_TEST_TABLE"(
        P_COL1 in VARCHAR2,
        P_COL2 out VARCHAR2
    ) IS
    BEGIN
        select  ORDER_NAME into P_COL2
         from ORDERS
         where ORDERS.ORDER_ID=P_COL1;
    END;


    原生ODBC需要这样才能调用基础存储过程(不带返回结果集)。

                        using (OdbcConnection connection = new OdbcConnection(connectionString))
                {
                    connection.Open();
    
                    using (OdbcCommand command = new OdbcCommand("CALL PROC_TEST_TABLE(?,?)", connection))
                    {
                        command.CommandType = CommandType.StoredProcedure;
    
                        // 添加存储过程的输入参数
                        command.Parameters.Add("P_COL1", OdbcType.NVarChar).Value = "3";
    
                        // 添加存储过程的输出参数
                        OdbcParameter outputParam = new OdbcParameter("P_XX1", OdbcType.NVarChar, 50);
                        outputParam.Direction = ParameterDirection.Output;
                        command.Parameters.Add(outputParam);
    
                        command.ExecuteNonQuery();
    
                        // 获取输出参数的值
                        string outputValue = (string)outputParam.Value;
                        Console.WriteLine("Output parameter value: " + outputValue);
    
                    }
                }


    SqlSugar里直接调用不行。

                SqlSugarClient db = new SqlSugarClient(new ConnectionConfig()
                {
                    ConnectionString = Config.ConnectionString,//Master Connection
                    DbType = SqlSugar.DbType.OceanBaseForOracle,//Oracle 模式用这个 ,如果是MySql 模式用DbType.MySql
                    InitKeyType = InitKeyType.Attribute,
                    IsAutoCloseConnection = true
                });
    
                var p = new SugarParameter("@P_COL1", "3");
                var p1 = new SugarParameter("@P_XX1", "1");
                p1.Direction = ParameterDirection.Output;
                p1.Size = 100;
    
                var dt1 = db.Ado.GetDataTable("CALL PROC_TEST_TABLE(@P_COL1,@P_COL2)",  p, p1  );
                var ret1 = p1.Value;


    0 回复
  • fate sta fate sta VIP0
    2023/11/8

    db.Ado.UseStoredProcedure().GetDataTable("CALL Proc_Test_table_return", p, p1, p2);

     这样和你ADO.NET应该一样

    0 回复
  • fate sta fate sta VIP0
    2023/11/8

    少了UseStoredProcedure

    0 回复
  • fate sta fate sta VIP0
    2023/11/8

    command.CommandType = CommandType.StoredProcedure; 等同于这个

    0 回复
  • 这个问题还没解决

    0 回复
  • @紫竹林:提供ADO.NET能跑的代码,我给你转成sqlsugar代码

    0 回复
  • string sql = "CALL PROC_TEST_TABLE(@nameP,@ageP)";

    var nameP = new SugarParameter("@P_COL1", "1");

    var ageP = new SugarParameter("@P_XX1", null, true);//设置为output

    var dt = db.Ado.UseStoredProcedure().GetDataSetAll("PROC_TEST_TABLE", nameP, ageP);//返回dt

    if (dt != null)

    {

        Console.WriteLine(dt.Tables[0].toString());

    }

    按照官网文档,测试报错:

    PROC_TEST_TABLE

    @P_COL1:1,@P_XX1:

    Program Exception:

    System.Data.Odbc.OdbcException (0x80131937): ERROR [42000] [ob-2.0.9][5.6.25]OBE-00900: You have an error in your SQL syntax; check the manual that corresponds to your OceanBase version for the right syntax to use near 'PROC_TEST_TABLE' at line 1

       at System.Data.Odbc.OdbcConnection.HandleError(OdbcHandle hrHandle, RetCode retcode)

       at System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior behavior, String method, Boolean needReader, Object[] methodArguments, SQL_API odbcApiMethod)

       at System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior behavior, String method, Boolean needReader)

       at System.Data.Odbc.OdbcCommand.ExecuteReader(CommandBehavior behavior)

       at System.Data.Odbc.OdbcCommand.ExecuteDbDataReader(CommandBehavior behavior)

       at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)

       at System.Data.Common.DbDataAdapter.Fill(DataSet dataSet, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior)

       at System.Data.Common.DbDataAdapter.Fill(DataSet dataSet)

       at SqlSugar.OceanBaseForOracle.OceanBaseForOracleDataAdapter.Fill(DataSet ds)

       at SqlSugar.AdoProvider.GetDataSetAll(String sql, SugarParameter[] parameters)

       at GbaseTest.Program.Main(String[] args) in C:\Users\Administrator\source\repos\sqlsugar-oceanbase-odbc\Program.cs:line 96

    Program End.


    0 回复
  • using SqlSugar;

    using System.Data;

    using System.Data.Odbc;


    namespace sqlsugar_oceanbase_odbc

    {

        public static class SqlSugarOdbcExtensions

        {

            /// <summary>

            /// 执行一个不返回结果集的存储过程,并获取输出参数的值(适用于 ODBC 连接)。

            /// 此方法绕过 SqlSugar 的内部处理,直接使用原生 OdbcCommand,避免因存储过程无结果集而引发的异常。

            /// </summary>

            /// <typeparam name="T">输出参数的类型</typeparam>

            /// <param name="db">SqlSugarClient 实例</param>

            /// <param name="procedureName">存储过程名称</param>

            /// <param name="setParameters">用于设置输入参数的委托(注意:不要在这里设置输出参数)</param>

            /// <param name="outputParameterName">输出参数名称(不含 @ 前缀)</param>

            /// <param name="outputDbType">输出参数的 OdbcType(如 OdbcType.NVarChar)</param>

            /// <param name="outputSize">输出参数的大小</param>

            /// <returns>输出参数的值,已转换为 T 类型</returns>

            public static T ExecuteStoredProcedureWithOutput<T>(

                this ISqlSugarClient db,

                string procedureName,

                Action<OdbcParameterCollection> setParameters,

                string outputParameterName,

                OdbcType outputDbType,

                int outputSize)

            {

                // 获取底层 ODBC 连接

                var connection = db.Ado.Connection as OdbcConnection;

                if (connection == null)

                    throw new InvalidOperationException("当前数据库连接不是 OdbcConnection,此扩展方法仅适用于 ODBC 数据源。");


                // 确保连接已打开(SqlSugar 通常会自动管理,但为安全起见,检查并打开)

                var needClose = connection.State != ConnectionState.Open;

                if (needClose)

                    connection.Open();


                try

                {

                    using (var command = new OdbcCommand(procedureName, connection))

                    {

                        command.CommandType = CommandType.StoredProcedure;


                        // 如果 SqlSugar 当前在事务中,将命令事务设置为相同的事务对象

                        if (db.Ado.Transaction != null)

                        {

                            command.Transaction = db.Ado.Transaction as OdbcTransaction;

                        }


                        // 调用委托设置输入参数

                        setParameters(command.Parameters);


                        // 添加输出参数

                        var outputParam = new OdbcParameter(outputParameterName, outputDbType, outputSize)

                        {

                            Direction = ParameterDirection.Output

                        };

                        command.Parameters.Add(outputParam);


                        // 执行命令(不返回结果集)

                        command.ExecuteNonQuery();


                        // 获取输出参数值并转换

                        object value = outputParam.Value;

                        if (value == null || value == DBNull.Value)

                            return default(T);

                        return (T)Convert.ChangeType(value, typeof(T));

                    }

                }

                finally

                {

                    // 如果之前由我们打开的连接,则关闭它(SqlSugar 会自动管理,但主动关闭也无妨)

                    if (needClose && connection.State == ConnectionState.Open)

                        connection.Close();

                }

            }

        }

    }

    ADO.NET能跑的代码,调用上面的方法可以。

      string output = db.ExecuteStoredProcedureWithOutput<string>(

          "CALL PROC_TEST_TABLE(?,?)",

          parameters =>

          {

              // 设置输入参数(注意:不要添加输出参数,扩展方法内部会添加)

              parameters.Add("P_COL1", OdbcType.NVarChar).Value = "1";

          },

          outputParameterName: "P_XX1",

          outputDbType: OdbcType.NVarChar,

          outputSize: 50

      );


      Console.WriteLine("Output parameter value: " + output);


    0 回复
  • @紫竹林

              var p1 = new SqlSugar.SugarParameter("@p1", "1");
              var outPut = new SqlSugar.SugarParameter("@p2", null, true) ;
              db.Ado.ExecuteCommand("CALL PROC_TEST_TABLE(@p1,@p2)", new List<SugarParameter>()
              {
                  p1,
                  outPut
              });
    
              Console.WriteLine(outPut.Value);

    差不多这样。

    0 回复
  • @fate sta:如果还不行需要线上能跑的DEMO删掉OBJ和BIN打包上传。 DEMO要求ADO.NET执行成功。

    0 回复
  • CALL PROC_TEST_TABLE(@p1,@p2)

    @p1:1,@p2:

    Program Exception:

    System.ArgumentNullException: Value cannot be null. (Parameter 'source')

       at SqlSugar.AdoProvider.ExecuteCommand(String sql, SugarParameter[] parameters)

       at SqlSugar.OceanBaseForOracle.OceanBaseForOracleProvider.ExecuteCommand(String sql, SugarParameter[] parameters)

       at SqlSugar.AdoProvider.ExecuteCommand(String sql, List`1 parameters)

       at GbaseTest.Program.Main(String[] args) in C:\Users\Administrator\source\repos\sqlsugar-oceanbase-odbc\Program.cs:line 112

    Program End.


    0 回复
  • var dt = db.Ado.UseStoredProcedure().GetDataSetAll("PROC_TEST_TABLE", nameP, ageP);//返回dt
    这种方式不支持oboracle吗

    0 回复
  • 0 回复
  • 有结果了吗?亲

    0 回复
  • @紫竹林

     var p1 = new SqlSugar.SugarParameter("@p1""1");
              var outPut = new SqlSugar.SugarParameter("@p2"nulltrue) ;
              db.Ado.ExecuteCommand("CALL PROC_TEST_TABLE(@p1,@p2)"new List<SugarParameter>()
              {
                  p1,
                  outPut
              });
     
              Console.WriteLine(outPut.Value);

    你按我的DEMO写了吗。我写给你的和你ADO.NET一样的。

    0 回复
  • 复制粘贴你的

    0 回复
  • 我测试代码都给你上传了

    0 回复