当我更新记录时,如何在数据库中防止重复记录?

3
在我的MySQL表中,我让它看起来像这样。
ControlNum|Title  |NumOfEpis|Description|
001       |naruto |500      |some text  |
002       |conan  |700      |some text  |

现在我在C#中创建了一个用户控件,其中用户被允许更新除主键“ControlNum”之外的所有列。假设每个列都有自己的文本框,在该用户控件中为了避免标题列中的重复,例如如果用户编辑第二行标题并将其命名为“Naruto”,那么它也将被复制。因此,我创建了一个名为checkData()的方法。
void checkData()
    {
        SuspendLayout();
        try
        {
            MySqlConnection conn = new MySqlConnection(myConnection);
            conn.Open();
            MySqlCommand command = new MySqlCommand("SELECT * FROM maindatabase.animelist where TitleAnime=?Title;", conn);
            //command.Parameters.AddWithValue("?CN", int.Parse(a.ToString()));
            command.Parameters.AddWithValue("?Title", textBox3.Text);
            MySqlDataReader reader = command.ExecuteReader();

            int ctr = 0;
            while (reader.Read())
            {
                ctr++;

            }
            if (ctr == 1)
            {
                my = Form.ActiveForm as MyList;
                my.msg = new Message_Box();
                my.msg.Descrip.Text = "Record is already in the Database";
                my.msg.Title.Text = "Duplicate Record";
                my.msg.ShowDialog();
            }
            else
            {

                updateData();
            }


            conn.Close();
            ResumeLayout();
        }
        catch (Exception ex)
        {
            MessageBox.Show("" + ex);
        }
    }


它原本是工作的,但我的问题是如果用户只更新了epis和descrip的数量,而并没有真正想要更新标题,我的方法仍然会检测到重复,因为我的逻辑是“if(ctr == 1)”..我认为我错过了一些方法或者我在错误的方法上..所以我希望有人能给我指点迷津..对于我这个新手感到抱歉Y.Y


1
在您的数据库中,在“Title”列上放置唯一约束。在您的代码中,捕获约束违规错误并向用户显示友好的错误消息。 - mbeckish
没有成为新手的问题...我总觉得自己一直都是个新手! :) 我会做的第一件事就是先考虑数据库解决方案。你需要做的是确保你有一个主键/标识,比如RowID之类的东西,然后你想使用UNIQUE CONSTRAINT。你可以在这里找到如何使用它们--> http://www.w3schools.com/sql/sql_unique.asp - waltmagic
@mbeckish 唯一约束?在我的数据库中,我看到了唯一索引,这是一样的吗?我该如何捕获错误?像 try catch 块一样吗? - Raymart Calinao
3个回答

2
您不希望有两个具有相同内容的标题。这可以通过在该列上使用唯一索引来自动实现。但是,如果您不想为此添加索引,那么可以更改查询方式。
SELECT ControlNum FROM maindatabase.animelist 
WHERE TitleAnime=?Title;

然后,您的逻辑还应检查ControlNum是否有差异。
int currentNum = int.Parse(a.ToString()));
while (reader.Read())
{
    int ctrlNum = reader.GetInt32(0);
    if(ctrlNum != currentNum)
        ctr++;

}
if (ctr > 0)
    ......

以这种方式,仅当检索到的ControlNum与您在界面中选择的ControlNum不同时,才会增加计数器。
另一种方法如下(请参见@mbeckish的下面评论)。
SELECT 1 FROM maindatabase.animelist 
WHERE TitleAnime=?Title AND ControlNum <> ?CN

command.Parameters.AddWithValue("?CN", int.Parse(a.ToString()));
command.Parameters.AddWithValue("?Title", textBox3.Text);
object result = command.ExecuteScalar();
if(result != null)
{
    // Found a record with different ControlNum but with the same title
    // Error here
}

这种方式可能比第一种更好,因为您不需要循环并且可以使用更简单、性能更高的ExecuteScalar来返回第一行第一列的值(在此情况下为1),而无需构建MySqlDataReader对象。


感谢这些教程。啊,我应该将更新方法或重复警告放在(ctr>0)的内部? - Raymart Calinao
目前的代码会警告重复。上面的代码如果当前记录与变量a中存储的ControlNum相同,则跳过控制变量的增量,因此,如果在读取循环之后控制变量仍为零,则您没有另一个与原始标题相同的标题,否则已经有一条记录(具有不同的ControlNum),该记录具有用户输入的标题。 - Steve
哦,谢谢,那么else部分就是更新了,我会试一下的。 - Raymart Calinao
为什么不在SQL查询中添加ControlNum <> currentNum呢?这样,您就可以只选择记录计数,并摆脱while循环。 - mbeckish
如果无法向数据库添加唯一约束,则更安全的方法是在事务内进行更新,在更新后检查重复项,然后回滚并引发错误(如果找到重复项)。 - Dave Manning

2

如果您的应用程序支持多个用户,您需要确保在检查重复项并更新数据库之间,其他用户不会进行更改。

最简单的方法是像 mbeckish 建议的那样,在标题列上创建唯一约束:

ALTER TABLE maindatabase.animelist 
ADD CONSTRAINT U_animelist_TitleAnime UNIQUE (TitleAnime)

数据库引擎将执行唯一标题的强制约束,您的客户端可以通过捕获任何违反约束的异常来处理用户反馈。
void checkData()
{
    SuspendLayout();
    try
    {

        updateData();

    }
    catch (Exception ex)
    {
        MySqlException sqlEx = ex as MySqlExecption;
        // If there is a constraint violation error.
        // (I may have the wrong error number, please test.)
        if (sqlEx != null && sqlEx.Number == 1062) 
        {
            my = Form.ActiveForm as MyList;
            my.msg = new Message_Box();
            my.msg.Descrip.Text = "Record is already in the Database";
            my.msg.Title.Text = "Duplicate Record";
            my.msg.ShowDialog();
        } 
        else 
        {
            MessageBox.Show("" + ex);
        }
    }
    finally
    {
        ResumeLayout();
    }
}

这就是正确的答案。Steve的代码解决方案可行,但你会给自己和数据库带来额外的工作量。 - waltmagic
1
同意,但我认为更重要的是另一种解决方案不可靠。如果/当出现问题时,很难向用户解释您的应用程序将防止重复标题,除非两个用户同时更改内容。如果不是由数据库引擎强制执行,则很难追踪重复的来源。只是想强调这一点,因为我遇到了许多这些问题,它们真的很烦人 :) - Dave Manning
哦,这里还有其他的解决方案啊。好的,我会尝试一下并检查结果。顺便说一句,谢谢你们帮助我 ^^, - Raymart Calinao
这是一些屏幕截图:http://www.mediafire.com/view/0n967b2ublnj32k/help.png或http://i61.tinypic.com/eulqty.png - Raymart Calinao
好像我解决了..只需将错误号更改为1062,它就完美地工作了。感谢您的代码。 - Raymart Calinao
显示剩余2条评论

0

更改查找重复项的SQL语句:

SELECT MAX(Title) as Count
FROM maindatabase.animelist
GROUP BY Title  , NumOfEpis, Description

如果计数大于1,则存在重复项。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接