存储过程从c#.net调用产生不同的结果

时间:2015-11-24 05:30:30

标签: c# mysql stored-procedures

-edit-写了一个更明确的解释,说明什么不是最底层的。也许只是跳过那个。

我遇到了我编写的存储过程的问题,并在我的c#应用程序中获得了结果,但是当我在MySQL基准测试中执行它时,结果返回正常。

首先程序是:

CREATE DEFINER=`root`@`localhost` PROCEDURE `GetNextOpponent`(IN p_user_id INT, OUT p_target_id INT, OUT p_target_data MEDIUMBLOB, OUT p_target_rank INT)
BEGIN
    DECLARE UserRank INT;

    CALL DeleteOldSearches(); /* TODO remove and call on interval instead of every time*/

    SET UserRank = (SELECT rank FROM world WHERE user_id = p_user_id);

    IF UserRank IS NOT NULL
    THEN
        SELECT user_id, world_data, rank
        INTO p_target_id, p_target_data, p_target_rank
        FROM world
        WHERE
            user_id != p_user_id  AND
            user_id NOT IN (SELECT target_id FROM searches WHERE user_id = p_user_id) AND
            shield < CURRENT_TIMESTAMP
        ORDER BY ABS(UserRank - 3)
        LIMIT 1;
    END IF;

    IF p_target_id IS NOT NULL 
    THEN
        INSERT INTO searches (user_id, target_id) 
        VALUES (p_user_id, p_target_id);
    END IF;

    /*SELECT TargetID, TargetData, TargetRank;*/
END

现在如果我在WorkBench中用

调用它
call battlecraft_test.GetNextOpponent(1, @p_target_id, @p_target_data, @p_target_rank);
select @p_target_id, @p_target_data, @p_target_rank;

我没有问题,获得了不错的结果

'3', BLOB, '2'

但是,如果我在我的应用程序中执行它,

        public static bool GetNextOpponent(int userID)
        {   
            MySqlConnection conn = null;

            try
            {
                conn = new MySqlConnection(ConnectionString);
                conn.Open();

                using (var cmd = new MySqlCommand("GetNextOpponent", conn) {CommandType = CommandType.StoredProcedure})
                {
                    cmd.Parameters.Add("@p_user_id", MySqlDbType.Int32).Value = userID;
                    cmd.Parameters.Add("@p_target_id", MySqlDbType.Int32).Direction = ParameterDirection.Output;
                    cmd.Parameters.Add("@p_target_data", MySqlDbType.MediumBlob).Direction = ParameterDirection.Output;
                    cmd.Parameters.Add("@p_target_rank", MySqlDbType.Int32).Direction = ParameterDirection.Output;

                    cmd.ExecuteNonQuery();

                    object a = cmd.Parameters["@p_target_id"].Value;    // null 
                    object b = cmd.Parameters["@p_target_data"].Value;  // null
                    object c = cmd.Parameters["@p_target_rank"].Value;  // null =(

                    return true;
                }
            }
            catch (Exception ex)
            {
                Logger.LogError($"Unexpected exception of type {ex.GetType()}: {ex.Message}");
                return false;
            }
            finally
            {
                conn?.Close();
            }
        }

out params全部为空。

有一些有趣的案例,我从我的应用程序中得到了结果,例如,如果我在调试时逐步执行每行代码,大多数时候没有任何反应。

我真的很挣扎,现在花了好几个小时 - 我的数据库知识并不像我现在的那样好,而且我已经离开了想法,所以我希望有人知道它可能是什么。

我试图解决此问题之一我尝试不使用OUT关键字,而只是返回字段并使用ExecuteReader,但它仍然只是有时有效。

如果我写另一个程序来包装这个程序,如下:

CREATE DEFINER=`root`@`localhost` PROCEDURE `test`(IN p_user_id INT)
BEGIN
    call battlecraft_test.GetNextOpponent(p_user_id, @p_target_id, @p_target_data, @p_target_rank);
    select @p_target_id, @p_target_data, @p_target_rank;
END

当我使用Reader执行它时它起作用,但是第一行总是为null而第二行有结果。这是一个可用的解决方法,但我宁愿找到它的原因。

感谢您提前做出任何回复。

-edit -

即使剥离它我也有问题。如果我将存储过程减少到

CREATE DEFINER=`root`@`localhost` PROCEDURE `GetNextOpponent`(IN p_user_id INT)
BEGIN
    SELECT user_id, world_data, rank
    FROM world
    WHERE
        user_id != p_user_id  AND
        user_id NOT IN (SELECT target_id FROM searches WHERE user_id = p_user_id) AND
        shield < CURRENT_TIMESTAMP
    ORDER BY ABS((SELECT rank FROM world WHERE user_id = p_user_id) - rank)
    LIMIT 1;
END

然后以读者身份进行

    public static bool GetNextOpponent(int userID)
    {
        MySqlConnection conn = null;

        try
        {
            conn = new MySqlConnection(ConnectionString);
            conn.Open();

            using (var cmd = new MySqlCommand("GetNextOpponent", conn))
            {
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.Parameters.Add("@p_user_id", MySqlDbType.Int32).Value = userID;

                //System.Threading.Thread.Sleep(1000); // Un-commenting this makes it work...

                using (var rdr = cmd.ExecuteReader())
                {
                    if (!rdr.Read())
                        return false; // returns here

                    var r1 = rdr.GetValue(0); // null
                    var r2 = rdr.GetValue(1); // null
                    var r3 = rdr.GetValue(2); // null

                    return true;
                }
            } 
        }
        catch (Exception ex)
        {
            Logger.LogError($"Unexpected exception of type {ex.GetType()}: {ex.Message}");
            return false;
        }
        finally
        {
            conn?.Close();
        }
    }

在工作台中执行它仍然会返回一个不错的结果

call battlecraft_test.GetNextOpponent(1);

1 个答案:

答案 0 :(得分:0)

您的代码中有许多需要改进的地方

在try / catch验证的finally块中关闭连接

不要使用泛型Catch作为第一级catch使用(“DatabaseSpecificExceptions”或“RunTimeExceptions”或任何其他Expected expection“并将其记录到文件或通过电子邮件发送到调试进一步

  public static bool GetNextOpponent(int userID)
    {   
        MySqlConnection conn = null;
        boolean resp ;

        //we assume that if fails
        resp = false ;

        try
        {
            conn = new MySqlConnection(ConnectionString);

    if(conn != null)
    {
            conn.Open();

            using (var cmd = new MySqlCommand("GetNextOpponent", conn) {CommandType = CommandType.StoredProcedure})
            {
            //Addding parameters to the SQL commands - good comments never hurt

                cmd.Parameters.Add("@p_user_id", MySqlDbType.Int32).Value = userID;
                cmd.Parameters.Add("@p_target_id", MySqlDbType.Int32).Direction = ParameterDirection.Output;
                cmd.Parameters.Add("@p_target_data", MySqlDbType.MediumBlob).Direction = ParameterDirection.Output;
                cmd.Parameters.Add("@p_target_rank", MySqlDbType.Int32).Direction = ParameterDirection.Output;

                        //you are executing a NonQuery but expectin results ??
                cmd.ExecuteNonQuery();

            //see comments above
                object a = cmd.Parameters["@p_target_id"].Value;    // null 
                object b = cmd.Parameters["@p_target_data"].Value;  // null
                object c = cmd.Parameters["@p_target_rank"].Value;  // null =(

                        //avoid returns in the middle of the flow until debug works
                //return true;
                        resp = true ;
            }
    }
        }
        catch (Exception ex)
        {
            Logger.LogError($"Unexpected exception of type {ex.GetType()}: {ex.Message}");
        }
        finally
        {
    if(conn != null)
            {
                conn?.Close();
            }
        }
    }