sql – ds.Tables.Rows.Add()在调用一次时产生3行

[注意更新:]

我希望用户向datagridview(DGV)添加新行将能够在Access数据库中创建该行,并且能够为这些新行创建多行和非同步编辑. DGV由数据集表填充,我发现在DGV和数据库之间设置数据是最佳实践(或者至少允许灵活性).

要对多个用户创建的新行进行编辑,数据集需要能够从数据库中检索自动增量主键,然后使用新行的更新键值重新填充DGV.或者至少这是我发现有这项工作的唯一方法.问题是,当我尝试向数据表添加一行时,最终会产生三行而不是一行.

[旧帖子因简洁而删除]

以下是DGV首次被填充并绑定到数据集的方式:

Dim ConMain As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MasterPath)
Dim ds As New DataSet

Public Sub UniversalFiller(ByVal QueryStringFill As String, ByVal DGV As DataGridView, ByVal AccessDBTableName As String)
    If IsNothing(ds.Tables(AccessDBTableName)) Then
    Else
        ds.Tables(AccessDBTableName).Clear()
    End If
    ConMain.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & MasterPath
    Dim daZZ As New OleDbDataAdapter(QueryStringFill, ConMain)
    Try
        daZZ.Fill(ds, AccessDBTableName)
        DGV.DataSource = ds
        DGV.DataMember = AccessDBTableName
        DGV.AutoResizeColumns()
    Catch ex As Exception
        WriteToErrorLog(ex.Message, ex.StackTrace, ex.GetHashCode, ex.Source, ex.ToString)
        ds.Clear
        MsgBox("There was an error filling the DGV, ds.cleared") 'this is for my notes, not user error'
    End Try

End Sub

更新:

我还是无法弄清楚这个问题.处理DGV.UserAddedRow时调用此方法. I’ve learned that原始代码可能不是添加1行的最佳方法,但即使制作New Row也遇到同样的问题:

Dim daZZ As New OleDbDataAdapter(DBSelectQuery, ConMain)
Dim CurrentCellPoint As Point = DGV.CurrentCellAddress
Dim CurrentCellText As String = DGV.CurrentCell.Value.ToString
Dim cmdBldr As New OleDbCommandBuilder(daZZ)
cmdBldr.QuotePrefix = "["
cmdBldr.QuoteSuffix = "]"
MsgBox("1")
Dim DaZZDataRow As DataRow = ds.Tables(DTName).NewRow
MsgBox("2")
DaZZDataRow(CurrentCellPoint.X) = CurrentCellText
MsgBox("3")
ds.Tables(DTName).Rows.Add(DaZZDataRow)
MsgBox("4")
daZZ.InsertCommand = cmdBldr.GetInsertCommand()
MsgBox("5")
daZZ.Update(ds.Tables(DTName))
MsgBox("6")
ds.Tables(DTName).Clear()
daZZ.Fill(ds, DTName)
MsgBox("5")
daZZ.Update(ds.Tables(DTName))
DGV.CurrentCell = DGV(CurrentCellPoint.X, CurrentCellPoint.Y)

问题始终是ds.Tables(DTName).Rows.Add()步骤.放在.Add()括号中的内容并不重要.它可以是数字或任何包括0的intiger,它将产生3行.它不会被多次调用.只需调用ds.Tables(DTName).Rows.Add().

如果这不是添加一个空行的正确方法,那是什么?我可以发布SQL插入/更新命令,但这不是问题,因为添加是三行而不是1.要清楚它只会运行一次MsgBox项并产生3行.

同样对我很好奇,InsertAt命令产生相同的结果:

ds.Tables(DTName).Rows.InsertAt(DaZZDataRow,CurrentCellPoint.Y)
而不是ds.Tables(DTName).Rows.Add()仍然产生3个新行.我也在Access的新临时数据库上试过这个并得到同样的问题.

Here is a working example of the code,作为VS2012项目加虚拟数据库.它是相当简单的,即没有错误处理,但它显示错误,并允许删除行作为一个额外的便利.感谢任何看过的人.

最佳答案 我对这个问题采用了回归基础的方法,更多地关注在添加新记录时让DataGridView显示生成的AutoNumber ID值的问题.我首先将一个DataGridView控件添加到我的表单,然后使用“添加项目数据源…”向导将其连接到我的Access数据库“Database1.accdb”中名为[Chemicals]的表. (问题中示例代码的早期版本引用了名为[Chemicals]的表,这就是我使用的.)

当我完成时,我的项目中有以下“东西”:

>我的表单上的DataGridView控件(dataGridView1),绑定到BindingSource(见下文)
>与我的Access数据库关联的DataSet(database1DataSet)
>一个BindingSource(chemicalsBindingSource),与database1DataSet中的[Chemicals]表相关联,用作DataGridView的DataSource
>一个TableAdapter(chemicalsTableAdapter)来管理DataSet和实际数据库之间的数据流.

该向导还在我的Form1_Load方法中给了我以下代码行. (我使用的是C#,但VB.NET非常相似.)

// TODO: This line of code loads data into the 'database1DataSet.Chemicals' table. You can move, or remove it, as needed.
this.chemicalsTableAdapter.Fill(this.database1DataSet.Chemicals);

这就是我运行应用程序并在DataGridView中查看现有记录所需的全部内容.

现在,要将DataGridView更新推送回数据库并检索新创建的记录的AutoNumber值,我使用了RowLeave事件.我发现UserAddedRow事件发生得太快(在用户开始输入新行之后立即),我想等到用户完成编辑行之前再对它做任何事情.

最后使用的代码如下(再次,C#)

private void Form1_Load(object sender, EventArgs e)
{
    fillErUp();
}

private void fillErUp()
{
    // (moved from Form1_Load to its own method so it could also be called from _RowLeave, below)
    // TODO: This line of code loads data into the 'database1DataSet.Chemicals' table. You can move, or remove it, as needed.
    this.chemicalsTableAdapter.Fill(this.database1DataSet.Chemicals);
}

private void dataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e)
{
    DataGridView dgv = (DataGridView)sender;
    if (dgv.IsCurrentRowDirty)
    {
        Cursor.Current = Cursors.WaitCursor;
        dgv.EndEdit();  // flush changes from DataGridView to BindingSource
        chemicalsBindingSource.EndEdit();  // flush changes from BindingSource to DataSet
        this.chemicalsTableAdapter.Update(this.database1DataSet);  // update database
        int currentRow = e.RowIndex;
        if (Convert.ToInt32(dgv.Rows[currentRow].Cells[0].Value) < 0)
        {
            // negative AutoNumber value indicates that the row has just been added
            int currentCol = e.ColumnIndex;
            fillErUp();  // re-fill the table in the DataSet, and hence the DataGridView as well
            dgv.CurrentCell = dataGridView1[currentCol, currentRow];
        }
        Cursor.Current = Cursors.Default;
    }
}

这肯定不是完整的生产代码,但我希望它有所帮助.

编辑重新:评论

我再次尝试了我之前的解决方案,看看我是否可以在不依赖任何Visual Studio“魔法”的情况下完成相同的结果.我这次的做法是:

>我打开了一个新的C#Windows Forms项目.
>我将DataSet对象,BindingSource对象和DataGridView对象拖放到空白表单上.它们分别命名为dataSet1,bindingSource1和dataGridView1.
>我创建了Form1_Load和dataGridView1_RowLeave事件处理程序,然后添加了我自己的代码,看起来像这样:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.OleDb;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace dgvTest2
{
    public partial class Form1 : Form
    {
        OleDbConnection con = new OleDbConnection();
        OleDbDataAdapter da = new OleDbDataAdapter();
        OleDbCommandBuilder cb;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            con.ConnectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Public\Database1.accdb";
            con.Open();
            da.SelectCommand = new OleDbCommand("SELECT * FROM Chemicals", con);
            cb = new OleDbCommandBuilder(da);
            cb.QuotePrefix = "["; cb.QuoteSuffix = "]";
            this.dataSet1.Tables.Add(new DataTable("Chemicals"));
            this.bindingSource1.DataSource = this.dataSet1;
            this.bindingSource1.DataMember = "Chemicals";
            this.dataGridView1.DataSource = this.bindingSource1;
            fillErUp();
        }

        private void fillErUp()
        {
            this.dataSet1.Tables["Chemicals"].Clear();
            da.Fill(this.dataSet1.Tables["Chemicals"]);
        }

        private void dataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e)
        {
            DataGridView dgv = (DataGridView)sender;
            if (dgv.IsCurrentRowDirty)
            {
                Cursor.Current = Cursors.WaitCursor;
                dgv.EndEdit();  // flush changes from DataGridView to BindingSource
                bindingSource1.EndEdit();  // flush changes from BindingSource to DataSet
                da.Update(this.dataSet1.Tables["Chemicals"]);  // update database
                int currentRow = e.RowIndex;
                if (dgv.Rows[currentRow].Cells[0].Value == DBNull.Value)
                {
                    // a null ID value indicates that the row has just been added
                    int currentCol = e.ColumnIndex;
                    fillErUp();  // re-fill the table in the DataSet, and hence the DataGridView as well
                    dgv.CurrentCell = dataGridView1[currentCol, currentRow];
                }
                Cursor.Current = Cursors.Default;
            }
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            con.Close();
        }
    }
}
点赞