【问题标题】:MySql "SET @variable" throwing Fatal Error in C# codeMySql“SET @variable”在 C# 代码中引发致命错误
【发布时间】:2011-10-29 18:40:35
【问题描述】:

我在使用 ExecuteNonQuery() 时遇到致命错误。 我是使用 sql 的新手,因此我不确定为什么这个 SET 命令会导致问题。

我使用的是 MySql 5.5.17,我在 VS2010 IDE 中使用的是 C# .Net Framework 3.5。

异常消息 = 命令执行期间遇到致命错误。 错误行 = SET @oldguid = 250006;

我使用的 sql 文件中的内容如下减去我删除的“cmets”:

DELETE FROM `disables` WHERE `sourceType`=0 AND `entry`=61904;
INSERT INTO `disables` (`sourceType`, `entry`, `flags`, `comment`) VALUES(0, 61904, 8, 'Magma Totem TEST - can crash client by spawning too many totems');
SET @oldguid = 250006;
SET @newguid = 202602;
UPDATE `creature` SET `guid`=@newguid WHERE `guid`=@oldguid;
UPDATE `creature_addon` SET `guid`=@newguid, `path_id`=@newguid*100 WHERE `guid`=@oldguid;
UPDATE `waypoint_data` SET `id`=@newguid*100 WHERE `id`=@oldguid*100;
UPDATE `areatrigger_teleport` SET `target_orientation`=2.255664 WHERE `id`=4386;
UPDATE `gameobject` SET `spawnMask`=3 WHERE `guid`=22674;

guid 列是无符号整数 (10)

我用来处理这个 .sql 文件的 C# 代码如下:

filename = lstBox_SqlFiles.SelectedItem.ToString();
mysql = new MySqlConnection(connection + Database);
string line;

OpenDatabase();
using (StreamReader reader = new StreamReader(filename))
{
  StringBuilder parsedLine = new StringBuilder();
  int count = 0;
  while ((line = reader.ReadLine()) != null)
  {
    if (line.Length > 0 && !line.StartsWith("--"))
    {
      if (line.EndsWith(";"))
      {
        if (parsedLine.Length > 0)
          line = parsedLine.ToString() + line;
        try
        {
          count++;
          lbl_LineQuery.Text = line;
          lbl_QueryCount.Text = String.Format("Count: {0}", count);

          MySqlCommand cmd = new MySqlCommand(line, mysql);
          cmd.ExecuteNonQuery();
        }
        catch (MySqlException ex)
        {
          string msg = String.Format("Source FileName: SqlUpdater.cs\nSql FileName: {0}\nError Line: {1}\nException Message: {2}\n", filename, line, ex.Message);
          MessageBox.Show("cmd.ExecuteNonQuery() Error!\n" + msg, "MySql Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
          return;
        }
        sbClear(parsedLine);
      }
      else
      {
        parsedLine.Append(line);
        continue;
      }
    }
    else
    continue;
  }
}

谁能看到我的代码有问题?我需要对“SET @var”字符串进行一些特殊操作吗?

任何帮助表示赞赏 提前致谢

路人

  • 编辑 * 作为旁注我应该指出,如果我使用像 SQLYog 这样的 sql 管理程序,它会毫无问题地处理相同的 sql 文件,所以我假设问题出在我的 C# 代码中的字符串操作中.

【问题讨论】:

  • 奇怪。在 mysql 监视器中手动运行时,设置的行完美运行。也许 C# mysql 库有问题。如果是这样的话,也许另一个 select @oldguid := 250006; 会绕过它。
  • 等一下,C# 代码是单独运行每一行的吗?
  • 您应该尝试逐步运行您的代码并检查每个变量的值以检测最终错误。另外,sbClear 函数有什么作用??
  • 我发布了一个解决方案,它有一个错误,我编辑了答案,现在可以了
  • GianT971 sbClear 函数只是一个自定义函数,用于清除 StringBuilder 以供重用。感谢您的帮助...

标签: c# mysql


【解决方案1】:

添加 ;Allow User Variables=True 到连接字符串。

【讨论】:

    【解决方案2】:

    这是我在将 MySql.Data.dll 从 1.0 升级到 6.9 时发现的问题。例如:

    MYSQL:

    SET @foo = 'foo'
    

    消息: 命令执行过程中遇到致命错误。

    我怀疑 MySql.Data 试图将 @foo 作为准备好的语句变量进行交互,并希望我填充它。关于死亡的痛苦。因此,解决方案似乎是告诉 MySql.Data 这是一个文字“@”而不是一个标记。

    可能还有其他方法,但我找到的实用解决方案是在反引号中引用变量名:

    SET @`foo` = 'foo'
    SELECT @`foo`
    

    我希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      其实我不认为你可以把这行SET @oldguid = 250006;传入一个mysqlcommand对象(其实我也不知道)。您应该做的是让您的程序将这些值放在一个局部变量中,然后替换更新查询中的参数。

      找到一种方法来混合你的代码和这个:

              // This line should be outside the While loop
              Dictionary<string, string> variables = new Dictionary<string, string>();
      
      
              if (line.Trim().ToUpper().StartsWith("SET"))
              {
                  List<string> commandLine;
                  commandLine = line.Trim(' ',';').Split().Distinct().ToList();
                  commandLine.Remove(string.Empty);
      
                  // After next line, the 'variables' dictionary contains the name 
                  // of the variable you want to set, and its value
                  variables[commandLine[1]] = commandLine[3];
      
                  // ...
                  // Do something here (try catch, chatever, but NO MySqlCommand)
                  // ...
              }
              else
              {
                  // If the line contains any of the variables you previously set,
                  // i will be the index of this variable, -1 otherwise
                  int i = line.ContainsAnyOfAt(variables.Keys);
                  while(i>=0)
                  {
                      // Here we replace the parameter by its value, for example:
                      // UPDATE `creature` SET `guid`=@newguid WHERE `guid`=@oldguid;
                      // becomes (after all loops):
                      // UPDATE `creature` SET `guid`=202602 WHERE `guid`=250006;
                      line = line.Replace(variables.Keys.ElementAt(i), variables.Values.ElementAt(i));
                      i = line.ContainsAnyOfAt(variables.Keys,i+1);
                  }
      
                  // ...
                  // This is where you should put the code of MySqlCommand
                  // ...
              }
      

      这里是扩展方法 ContainsAnyOfAt :

              public static int ContainsAnyOfAt<T>(this global::System.String source, IEnumerable<T> values, int startIndex = 0)
              {
                  if (source == null) throw new ArgumentNullException("source");
                  for (int i = startIndex ; i < values.Count(); i++)
                  {
                      if (source.Contains(values.ElementAt(i).ToString()))
                      {
                          return i;
                      }
                  }
                  return -1;
              }
      

      请试一试并提供反馈。 问候

      【讨论】:

      • 这是一个范围界定问题。这个答案不能解决这个问题。
      • 感谢 GianT971,您的示例代码正是我所需要的,我花了一段时间,我不得不进行一些修改才能让它工作,但它现在可以工作了,非常感谢。我基本上取消了 ContainsAnyOfAt(只是移动了一些示例代码)并将 while 循环更改为 foreach(变量中的 KeyValuePair kvpPair)。再次感谢您的示例代码。我会给你的回复投票,但显然你自己必须有 15 个代表才能投票给其他人。
      • 已在此线程中解决:stackoverflow.com/questions/5524632/…
      【解决方案4】:

      代码基本上是这样的:

      • 将文件中的所有 SQL 命令加载到字符串集合中。
      • 从顶部遍历该集合:
        • 创建一个新的MySqlCommand(从而创建自己的范围!)
      • MySQL 在代码的第 3 行抛出错误,因为变量 @oldguid 尚未声明。

      如果您希望能够使用变量,请使用一个 MySqlCommand 对象,并调用一次ExecNonQuery()

      最好的办法是创建一个存储过程。也许您的“guid”/整数值需要 2 个参数。

      它在 SQLYog 中起作用的原因是所有这些语句都在相同的上下文中运行,而不是在不同的会话中。

      【讨论】:

      • p.campbell 感谢您的解释,我从来没有想过使用范围的 MySqlCommand,就像我说我是使用 MySql 的新手,再次感谢您的回复。
      【解决方案5】:

      Андрей 的建议对我有用。

      我的 MySQL 数据库中有一个相当复杂的过程,我不想将其包含在我的 C# 代码中。这是我的做法:

      //Open connection
      string conString = "server=myserver; Uid=myusername; database=myscheme; Pwd=mypwd";
      MySqlConnection con = new MySqlConnection(conString);
      
      try
      {
          //Set first variable, @START
          string sql = "SET @START = '" + date1 + "'";
          MySqlScript cmd = new MySqlScript(con, sql);
          cmd.Connection.Open();
          cmd.Execute();
      
          //Set second variable, @END
          sql = "SET @END = '" + date2 + "'";
          cmd = new MySqlScript(con, sql);
          cmd.Execute();
      
          //Send procedure call
          MySqlDataAdapter MyDA = new MySqlDataAdapter();
          sql = "call MY_DB_PROCEDURE";
          MyDA.SelectCommand = new MySqlCommand(sql, con);
      
          //From here you can process the DB response as you want
          //For instance, display the results in a datagridview
          DataTable table = new DataTable();
          MyDA.Fill(table);
      
          BindingSource bSource = new BindingSource();
          bSource.DataSource = table;
      
          //"dataGridView1" is already placed in the active form
          dataGridView1.DataSource = bSource;
          dataGridView1.Visible = true;
      
      }
      catch (Exception e)
      {
          //Error handling procedure
      }
      finally
      {
          if (con.State == ConnectionState.Open)
          {
              con.Dispose(); // return connection to the pool
          }
      }
      

      编辑

      更优雅的解决方案是在连接字符串中添加“Allow User Variables=True”。 示例如下:

      //Open connection
      string conString = "server=myserver; Uid=myusername; database=myscheme; Pwd=mypwd; Allow User Variables=True";
      MySqlConnection con = new MySqlConnection(conString);
      
      try
      {
          //Open connection
          con.Open();
      
          //Set first variable, @START
          //Set second variable, @END
          //Send procedure call
          string sql = "SET @START = '" + date1 + "';" +
                       "SET @END   = '" + date2 + "';" +
                       "CALL MY_DB_PROCEDURE";
      
          MySqlDataAdapter MyDA = new MySqlDataAdapter();
          MyDA.SelectCommand = new MySqlCommand(sql, con);        
      
          //From here you can process the DB response as you like
          //...
      
      
      }
      catch (Exception e)
      {
          //Error handling procedure
      }
      finally
      {
          if (con.State == ConnectionState.Open)
          {
              con.Dispose(); // return connection to the pool
          }
      }
      

      【讨论】:

        【解决方案6】:

        编写包含变量(@name_var)的过程。抛出异常。帮助更改类 MySqlCommand 类 MySqlScript

        【讨论】:

        • 我给了你一个 +1 来删除减号,并添加了一个示例代码。
        【解决方案7】:

        添加连接字符串;允许用户变量=True

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-10-26
          • 2011-04-13
          • 1970-01-01
          • 1970-01-01
          • 2017-08-02
          • 2021-10-13
          • 1970-01-01
          相关资源
          最近更新 更多