繁体   English   中英

MySql“SET @variable”在C#代码中抛出致命错误

[英]MySql “SET @variable” throwing Fatal Error in C# code

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

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

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

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

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列是unsigned int(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.Data.dll从1.0升级到6.9时发现的问题。 例如:

MYSQL:

SET @foo = 'foo'

消息:命令执行期间遇到致命错误。

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

可能还有其他方法,但我发现的实用解决方案是引用后引号中的变量名称:

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

我希望这有帮助。

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

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

我的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
    }
}

编辑

更优雅的解决方案是在连接字符串中添加“允许用户变量= 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
    }
}

实际上,我认为你不能通过这一行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;
        }

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

代码基本上是这样的:

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM