【问题标题】:Cannot delete apostrophe from string to make MySQL query work in C#无法从字符串中删除撇号以使 MySQL 查询在 C# 中工作
【发布时间】:2018-08-27 22:34:53
【问题描述】:

我正在做一个项目,我在字符串类中使用 mp3 歌曲的元数据。这些是我想要复制到 mySQL 数据库(来自我从数据中创建的列表)中的数据(即艺术家、标题等),我有下一个查询:

SELECT * FROM database.tablename WHERE artist='"+song[i].artist+ "' AND title='" + song[i].title + "' AND genre='"+song[i].genre+"';

代码完美运行(知道成功复制了 12 行),直到 for 循环到达一首包含撇号 (') 的歌曲,它在给定符号处出现语法错误而退出。例如:song[i].title 是我不是她。我尝试了我能想象的一切:

  1. 我尝试将 ' 替换为 string.empty
  2. 试图替换为“”
  3. 甚至尝试替换为“''”(2 个撇号),以便查询可以识别撇号,但似乎没有任何帮助(总是出现相同的语法错误,例如即使没有替换)

这是一行,所以你可以看看我是如何尝试的: song[i].artist = song[i].artist.Replace("'","");

所以我的问题是:有什么解决方案可以去掉撇号,或者有什么方法可以使查询工作吗?

编辑:这是我的原始代码(只有 for 循环)以便更好地理解。

for (int i = 0; i < Array.Length; i++)
            {
                Command = @"SELECT * FROM database.tablename WHERE artist='"+song[i].artist+ "' AND title='" + song[i].title + "' AND genre='"+song[i].genre+"';";
                MySqlCommand myCommand = new MySqlCommand(Command);
                using (MySqlConnection mConnection = new MySqlConnection(ConnectionString.ToString()))
                {
                    adapter = new MySqlDataAdapter(Command,mConnection);
                    mConnection.Open();
                    adapter.Fill(dataset);
                    int adat = dataset.Tables[0].Rows.Count;
                    if (adat <= 0)       //if current data does not exist
                    {
                        song[i].artist = song[i].artist.Replace("'","\'");
                        song[i].title = song[i].title.Replace("'", "\'");
                        song[i].genre = song[i].genre.Replace("'", "\'");
                        myCommand = new MySqlCommand("INSERT INTO database.tablename (artist,title,length,genre) VALUES ('"+song[i].artist+"','"+song[i].title+"','"+song[i].length+"','"+song[i].genre+"');",mConnection);
                        myCommand.ExecuteNonQuery();
                        dataset.Clear();
                    }
                    mConnection.Close();
                }
            }

这就是我“使用”的东西(抱歉,不知道如何让它看起来合适):

使用系统; 使用 System.Collections.Generic; 使用 System.ComponentModel; 使用 System.Data; 使用 System.Drawing; 使用 System.Linq; 使用 System.Text; 使用 System.Threading.Tasks; 使用 System.Windows.Forms; 使用 System.IO; 使用标签库; 使用 TagLib.Id3v2; 使用 System.Configuration; 使用 System.Data.SqlClient; 使用 MySql; 使用 MySql.Data; 使用 MySql.Data.MySqlClient; 使用 Programname.Properties;

【问题讨论】:

  • 尝试使用您正在使用的任何技术查找“参数化查询”(您没有显示实际代码,所以不知道您正在使用哪些库,或者我会将您链接到一个)。除了其他几个好处之外,它们还可以让您将字符串放入数据库中,无论格式如何。
  • 也许这个link 会帮助你,用“'”引用的字符串中的“'”可以写成“''”。
  • 双撇号应该可以。您是否复制了正在生成值的 sql 查询并在 mysql 中运行它以查看它是否在那里工作?
  • 你试过了吗:Field.Replace("'", "''")
  • 清关: 1. 我在 MySQL 工作台中测试了查询,它与其他数据库一起工作没有问题。 2. 因为我写了 90% 的 mp3 元数据,所以我很清楚它是一个撇号

标签: c# .net string replace apostrophe


【解决方案1】:

只需将与数据提供者无关的解决方案添加到组合中,您就可以采用这种方法将代码与 MySql 分离。

ConnectionString 可以在 app/web.config 中设置:

<connectionStrings>
  <add name="Example" providerName="MySql.Data.MySqlClient" connectionString="Data Source=1.1.1.1"/>
</connectionStrings>

并且代码将使用System.Data.Common 类:

var connectionSettings = ConfigurationManager.ConnectionStrings["Example"];
var dbFactory = DbProviderFactories.GetFactory(connectionSettings.ProviderName);

using (DbConnection connection = dbFactory.CreateConnection(connectionSettings.ConnectionString))
using (DbCommand countCommand = connection.CreateCommand())
{
    string sql = @"
SELECT COUNT(*) 
FROM database.tablename 
WHERE artist=@artist AND title=@title 
AND genre=@genre";

    countCommand.CommandText = sql;
    countCommand.Parameters.Add(dbFactory.GetParameter("@artist", null));
    countCommand.Parameters.Add(dbFactory.GetParameter("@title", null));
    countCommand.Parameters.Add(dbFactory.GetParameter("@genre", null));

    for (int i = 0; i < songs.Length; i++)
    {
        var song = songs[i];

        countCommand.Parameters["@artist"].Value = song.artist;
        countCommand.Parameters["@title"].Value = song.title;
        countCommand.Parameters["@genre"].Value = song.genre;

        int matches = (int)countCommand.ExecuteScalar();
        if (matches == 0)
            continue;

        using (DbCommand insertCommand = connection.CreateCommand())
        {
            string insertSql = @"
INSERT INTO database.tablename(artist, title, length, genre) 
VALUES(@artist, @title, @length, @genre";

            insertCommand.CommandText = insertSql;
            insertCommand.Parameters.Add(dbFactory.GetParameter("@artist", song.artist));
            insertCommand.Parameters.Add(dbFactory.GetParameter("@title", song.title));
            insertCommand.Parameters.Add(dbFactory.GetParameter("@length", song.length));
            insertCommand.Parameters.Add(dbFactory.GetParameter("@genre", song.genre));

            int result = insertCommand.ExecuteNonQuery();
        }
    }
}

您可以创建自定义扩展,提供比DbProviderFactory 提供的选项更好的选项:

public static class FactoryExtensions
{
    public static DbParameter GetParameter(this DbProviderFactory factory, string name, object value)
    {
        var param = factory.CreateParameter();
        param.Value = value ?? DBNull.Value;
        param.Name = name;
        return param;
    }

    public static DbConnection CreateConnection(this DbProviderFactory factory, string connectionString, bool open = true)
    {
        DbConnection connection = factory.CreateConnection();
        connection.ConnectionString = connectionString;

        if (open)
            connection.Open();

        return connection;
    }
}

显然您的代码比您提供的示例更复杂,但这是一个起点。

【讨论】:

  • 经过一些试验和错误后,根据您的代码,我最接近解决方案的是我在 for 循环的第一行收到一条消息:附加信息:找不到参数'@artist'在集合中。
  • @GyörgyTurbék 这是因为我忘记在我的示例中设置参数名称。您需要添加param.Name = name,请参阅我的更新答案。
  • 感谢您的快速回复!我现在唯一的问题是我的代码在两个答案的某个地方都卡住了(内存使用量增加了,然后什么也没发生),但是一旦我明天弄清楚(我需要睡觉),我会及时通知你。
  • 好的,我完全不知道如何以及为什么,但是通过对您提供的代码进行一些更改,我终于能够让一切正常工作。非常感谢,您可能刚刚保存了我的论文。
  • 在您的 SQL 语句中使用参数是这对您有用的原因。如果你使用这些,撇号转义不需要发生。此外,您消除了 SQL 注入攻击,因此您应该始终使用参数。我的回答主要是展示System.Data.Common 技巧。
【解决方案2】:

正如@Chad 所说,参数是要走的路。

使用标准的 System.Data 类,您可能会看到如下内容:

// set up command using @parameters
using (SqlCommand cmd = new SqlCommand("SELECT * FROM database.tablename WHERE artist=@artist AND title=@title AND genre=@genre", connection))
{
    // add parameter values to command
    cmd.Parameters.Add(new SqlParameter("@artist", song[i].artist));
    cmd.Parameters.Add(new SqlParameter("@title", song[i].title));
    cmd.Parameters.Add(new SqlParameter("@genre", song[i].genre));

    SqlDataReader reader = cmd.ExecuteReader();

    // do useful stuff here
}

我从here 找到(然后删掉了)一个 MySQL 连接器/NET 教程,它可能更特定于 MySQL:

string connStr = "*** your connection string here ***";
MySqlConnection conn = new MySqlConnection(connStr);
conn.Open();

string sql = "SELECT * FROM database.tablename WHERE artist=@artist AND title=@title AND genre=@genre";
MySqlCommand cmd = new MySqlCommand(sql, conn);

cmd.Parameters.AddWithValue("@artist", song[i].artist);
cmd.Parameters.AddWithValue("@title", song[i].title);
cmd.Parameters.AddWithValue("@genre", song[i].genre);

MySqlDataReader rdr = cmd.ExecuteReader();

// do useful stuff here

rdr.Close();
conn.Close();

【讨论】:

  • 如果可以避免的话,也不要硬编码数据提供者特定的类。
  • 信不信由你,但仍然是同样的错误: 附加信息:您的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在第 1 行的 'm Not Her (Hook N Sling Remix)','00:03:16.0670000','House')' 附近使用正确的语法 - 就在撇号处再次。
  • 这很奇怪。只是为了确认(抱歉),您使用了 INSERT 查询和 SELECT 的参数?
  • @NigelWhatling 是的,我也怀疑这一点
  • 一方面你是对的,我忘了更改 INSERT 查询(对不起,我深夜了),另一方面,我的代码卡在某个地方,调用堆栈只给了我“Application.Run(新表格 1());"行,所以明天需要更多的挖掘
猜你喜欢
  • 2022-11-15
  • 2021-12-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多