使用 C# 和 SQL 解决 datagridview 中重复条目的最佳方法是啥?

Posted

技术标签:

【中文标题】使用 C# 和 SQL 解决 datagridview 中重复条目的最佳方法是啥?【英文标题】:What is the best way to account for duplicate entries in datagridview with C# and SQL?使用 C# 和 SQL 解决 datagridview 中重复条目的最佳方法是什么? 【发布时间】:2021-05-04 12:46:34 【问题描述】:

此 Windows 应用程序在 datagridview 中显示学生信息。双击表格时,会出现另一个表格,用于编辑数据。

当 StudentName 存在重复项时,双击最新条目时,仅显示 StudentName 最早的条目。此外,在编辑特定学生的任何数据时,所有重复的条目也会被编辑!

我正在尝试修改代码,以便它根据 StudentId 而不是 StudentName 加载数据。另一种想法是对代码进行更改,以便用户不能输入重复的条目。

解决这个问题的最佳方法是什么?

ViewStudentForm.cs

private void StudentDataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)

    if(StudentDataGridView.Rows.Count > 0)
    
    string studentName = StudentDataGridView.SelectedRows[0].Cells[1].Value.ToString();

    StudentForm studentForm = new StudentForm();
    studentForm.StudentName = studentName;
    studentForm.IsUpdate = true;
    studentForm.ShowDialog();
    LoadDataIntoDataGridView();
    


private void LoadDataIntoDataGridView()

    using (SqlConnection con = new SqlConnection(AppConnection.GetConnectionString()))
    
        using (SqlCommand cmd = new SqlCommand("usp_Students_LoadDataIntoDataGridView", con))
        
            cmd.CommandType = CommandType.StoredProcedure;

            if (con.State != ConnectionState.Open)
                con.Open();
                    
            DataTable dtStudents = new DataTable(); 
            SqlDataReader sdr = cmd.ExecuteReader(); 
            dtStudents.Load(sdr);
            StudentDataGridView.DataSource = dtStudents;                   
        
    

StudentForm.cs

public string StudentName  get; set; 
public bool IsUpdate  get; set; 

private void SaveButton_Click(object sender, EventArgs e)

    //Do Insert Process
    using (SqlConnection con = new SqlConnection(AppConnection.GetConnectionString())) 
    
        using (SqlCommand cmd = new SqlCommand("usp_Students_InsertNewStudent", con))
        
            cmd.CommandType = CommandType.StoredProcedure;

            cmd.Parameters.AddWithValue("@StudentName", StudentNameTextBox.Text.Trim());
            cmd.Parameters.AddWithValue("@Age", AgeTextBox.Text.Trim());
            cmd.Parameters.AddWithValue("@Gender", GenderTextBox.Text.Trim());
            cmd.Parameters.AddWithValue("@Description", DescriptionTextBox.Text.Trim());
                            
        if (con.State != ConnectionState.Open)
            con.Open();

            cmd.ExecuteNonQuery();

            MessageBox.Show("Student is successfully added in the database.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
            ResetFormControl();
       
   

usp_Students_InsertNewStudent 的存储过程

ALTER PROCEDURE [dbo].[usp_Students_InsertNewStudent]
(
    @StudentName NVARCHAR(200)
    ,@Age NVARCHAR(50)
    ,@Gender NVARCHAR(50)
    ,@Description NVARCHAR(MAX)
    ,@Image IMAGE
    ,@CreatedBy NVARCHAR(50)
)
AS
    BEGIN
        INSERT INTO [dbo].[Students]
           ([StudentName]
           ,[Age]
           ,[Gender]
           ,[Description]
           ,[Image]
           ,[CreatedBy]
           ,[CreatedDate])
     VALUES
        (
            @StudentName
            ,@Age
            ,@Gender
            ,@Description
            ,@Image
            ,@CreatedBy
            ,GETDATE()
        )
    END

【问题讨论】:

有很多方法可以解决这个问题。我会在数据库端进行数据验证,因为我认为多个客户端可以同时访问数据库。恕我直言,usp_Students_InsertNewStudent 应该返回插入是否发生。并且模式应该有约束防止你不想进入表的重复项。 没有足够的信息来回答您的问题 首先,我认为您需要对学生姓名列进行唯一约束。这将防止重复。至于如何更改存储过程,这取决于你。数据完整性是第一位的。当您违反上述约束时,您可以简单地捕获 specific 异常并告诉用户这是一个重复的学生姓名。 IMO 试图对 StudentName 施加唯一约束是一个错误的想法。人们有重复的名字,这是事实或生活。您会遇到许多重复的常用名称,例如“John Smith”。似乎双击处理程序应该提取 StudentId 并将其传递给 StudentForm 详细信息。同样,插入存储过程应该捕获scope_identity(),以便它可以通过output 参数返回新插入记录的StudentId rel - 不要使用addwithvalue。 【参考方案1】:

一些事情:

    您需要确定现实世界中对您的学生构成独特性的事物。即使是学生姓名、年龄和性别的组合也不会是唯一的。这就是为什么学校会给出一个唯一标识学生的学生 ID。一旦您知道那是什么,就将其添加到您的表中并对其施加唯一约束。 设置后,您需要在前端进行验证,以防止在用户发送重复数据时在数据库中发生错误。这看起来是一个桌面应用程序,前端和后端之间没有层所以应该尽快检查数据库并立即给用户反馈。 如果出于某种原因,您不能执行 #2,那么在您的存储过程中,您可以在插入之前检查是否存在,因为如果您不检查,您的约束将抛出一个错误,如果未处理将使您的应用崩溃。
ALTER PROCEDURE [dbo].[usp_Students_InsertNewStudent]
(
    @StudentName NVARCHAR(200)
    ,@Age NVARCHAR(50)
    ,@Gender NVARCHAR(50)
    ,@Description NVARCHAR(MAX)
    ,@Image IMAGE
    ,@CreatedBy NVARCHAR(50)
)
AS
BEGIN
   if not exists (select 'x' from dbo.Students where uniquekey=@passedinuniquekey)
   BEGIN
        INSERT INTO [dbo].[Students]
           ([StudentName]
           ,[Age]
           ,[Gender]
           ,[Description]
           ,[Image]
           ,[CreatedBy]
           ,[CreatedDate])
     VALUES
        (
            @StudentName
            ,@Age
            ,@Gender
            ,@Description
            ,@Image
            ,@CreatedBy
            ,GETDATE()
        )
    END
END

最后,我会在调用这个存储过程的实际代码中这样做

    int rowsAffected = cmd.ExecuteNonQuery();
    if (rowsAffected>0)
    
            MessageBox.Show("Student is successfully added in the database.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
            ResetFormControl();
    
    else
    // Failed message here

【讨论】:

【参考方案2】:

我为 ViewStudentForm.cs 中的双击处理程序更改了一些代码

在这种情况下,我认为根据 Id 而不是学生姓名执行加载操作会更好。

private void StudentDataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)

    if(StudentDataGridView.Rows.Count > 0)
    
        int StudentId = Convert.ToInt32(StudentDataGridView.SelectedRows[0].Cells[0].Value);            
        StudentForm studentForm = new StudentForm();
        studentForm.StudentId = StudentId;
        studentForm.IsUpdate = true;
        studentForm.ShowDialog();
        LoadDataIntoDataGridView();
     

【讨论】:

这不是“更好”。 逻辑上正确使用要传递给另一个“进程”以执行某些操作的实体的主(或备用)键值。不要开始做出假设并传递任何东西。您的表单上是否没有某种编辑按钮可以执行完全相同的操作?也许是 rt-click 的弹出菜单?你要把相同的代码放在多个地方吗?

以上是关于使用 C# 和 SQL 解决 datagridview 中重复条目的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

winform c# Datagridview 选中行 急!!!

使用 c# 和 oledb 查询更新 Ms-Access 2010 中的列值

使用 C# 和 SQL 解决 datagridview 中重复条目的最佳方法是啥?

如何实现c# winform DataGridView添加一行,添加数据后,保存到数据库?

C# radioButton怎么使用?怎么关联到dataGridView

c#DataGridVie垂直滚动条为啥不能拖动了?