如何使用自动递增键更新update语句的并发问题?

时间:2011-01-22 06:12:17

标签: sql sql-server database visual-c#-express-2010

我在运行时使用我的新手的Sql / Visual C#数据库程序遇到以下错误消息:

并发冲突:UpdateCommand影响了预期的1条记录中的0条。

我已经对这个问题进行了一些搜索,并且已经看到了几个关于它的线索,但它们还不足以让我解决这个问题。我注意到人们在谈论当你使用自动递增主键时经常会发生的事情。这个程序就是这种情况。此外,没有多线程或其他任何类似的东西,我正在编写这个程序。因此,我认为自动增量可能是唯一的问题。

话虽如此,尽管有自动增量,我怎样才能让update命令工作?在数据库编程方面我几乎站不起来,所以如果你不介意的话请详细说明。我正在使用的命令是通过SqlCommandBuilder对象。我已经将该对象设置为新的SqlCommandBuilder(DataAdapter),并且我没有做任何特别的事情。

感谢。


此编辑是第二个。第一个是在下面。

由于我对数据库编程经验不足,我无法肯定地说出这一点。但是我有充分的理由相信我遇到的问题与新的行没有完全添加到数据库,直到程序终止。我不明白他们为什么要等到程序终止才能这样做,或者如果他们等到那时,那么程序的终止到底是什么导致它们突然被完全保存。但是我忘了提到这个错误只发生在我在程序的特定执行过程中添加的行上。如果该行已经在先前的执行中添加或者通过预先存在的表数据添加,那么一切都很好。我使用delete方法得到了同样的错误,它也只出现在新行中。

如何将这些行完全保存到所有内容中,以免发生这种情况?该程序的终止是什么导致这些行被完全保存?谢谢!


由于请求,我在这里留下了两个代码片段。第一个是问题发生的方法。下一个将包括整个班级。整个程序中只有两个类,而另一个类在这个特定问题上对我来说似乎并不重要。

    private void btnUpdate_Click(object sender, EventArgs e)
    {
        if (recordShown)
        {
            con.Open();

            currentRow[1] = tbFirstName.Text;
            currentRow[2] = tbMiddleName.Text;
            currentRow[3] = tbLastName.Text;
            currentRow[4] = tbSuffix.Text;
            currentRow[5] = tbHomePhone.Text;
            currentRow[6] = tbCellPhone.Text;
            currentRow[7] = tbOtherPhone.Text;
            currentRow[8] = tbStreetAddress.Text;
            currentRow[9] = tbCityAndState.Text;
            currentRow[10] = tbCountry.Text;
            currentRow[11] = tbEmail.Text;

            dAdapter.Update(dataset, "Contacts");

            con.Close();
        }
        else
        {
            MessageBox.Show("Please locate/add a record first.");
        }
    }

下一个片段:

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

namespace Dakota
{
public partial class Form1 : Form
{
    SqlConnection con;
    DataSet dataset;
    SqlDataAdapter dAdapter;
    DataRow currentRow;
    string primaryKey;
    SqlCommandBuilder cmdBuilder;
    bool recordShown = false;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        dataset = new DataSet();
        con = new SqlConnection();

        con.ConnectionString = "Data Source=.\\SQLEXPRESS;" +
            "AttachDbFilename=C:\\Users\\Sterling\\Documents\\Contacts.mdf;" +
            "Integrated Security=True;Connect Timeout=30;User Instance=True";

        con.Open();

        string getData = "SELECT * FROM tblContacts";
        dAdapter = new SqlDataAdapter(getData, con);
        dAdapter.Fill(dataset, "Contacts");
        cmdBuilder = new SqlCommandBuilder(dAdapter);
        cmdBuilder.ConflictOption = ConflictOption.OverwriteChanges;

        con.Close();
    }

    private void clearTextBoxes()
    {
        tbFirstName.Clear();
        tbMiddleName.Clear();
        tbLastName.Clear();
        tbSuffix.Clear();
        tbHomePhone.Clear();
        tbCellPhone.Clear();
        tbOtherPhone.Clear();
        tbStreetAddress.Clear();
        tbCityAndState.Clear();
        tbCountry.Clear();
        tbEmail.Clear();
    }

    private void fillTextBoxes(int row)
    {
        DataRow dr = dataset.Tables["Contacts"].Rows[row];
        tbFirstName.Text = dr.ItemArray.GetValue(1).ToString();
        tbMiddleName.Text = dr.ItemArray.GetValue(2).ToString();
        tbLastName.Text = dr.ItemArray.GetValue(3).ToString();
        tbSuffix.Text = dr.ItemArray.GetValue(4).ToString();
        tbHomePhone.Text = dr.ItemArray.GetValue(5).ToString();
        tbCellPhone.Text = dr.ItemArray.GetValue(6).ToString();
        tbOtherPhone.Text = dr.ItemArray.GetValue(7).ToString();
        tbStreetAddress.Text = dr.ItemArray.GetValue(8).ToString();
        tbCityAndState.Text = dr.ItemArray.GetValue(9).ToString();
        tbCountry.Text = dr.ItemArray.GetValue(10).ToString();
        tbEmail.Text = dr.ItemArray.GetValue(11).ToString();
    }

    private void fillTextBoxes(DataRow dr)
    {
        tbFirstName.Text = dr.ItemArray.GetValue(1).ToString();
        tbMiddleName.Text = dr.ItemArray.GetValue(2).ToString();
        tbLastName.Text = dr.ItemArray.GetValue(3).ToString();
        tbSuffix.Text = dr.ItemArray.GetValue(4).ToString();
        tbHomePhone.Text = dr.ItemArray.GetValue(5).ToString();
        tbCellPhone.Text = dr.ItemArray.GetValue(6).ToString();
        tbOtherPhone.Text = dr.ItemArray.GetValue(7).ToString();
        tbStreetAddress.Text = dr.ItemArray.GetValue(8).ToString();
        tbCityAndState.Text = dr.ItemArray.GetValue(9).ToString();
        tbCountry.Text = dr.ItemArray.GetValue(10).ToString();
        tbEmail.Text = dr.ItemArray.GetValue(11).ToString();
    }

    private void btnSearch_Click(object sender, EventArgs e)
    {
        string searchFor = tbSearchFor.Text;
        string column;
        if (rbFirstName.Checked)
        {
            column = "firstName";
        }
        else
        {
            column = "lastName";
        }

        DataRow[] rows = dataset.Tables["Contacts"].Select(column + "='" + searchFor + "'");
        int number = rows.Length;

        if (number == 0)
        {
            MessageBox.Show("No such records were found.");
        }
        else if (number > 1)
        {
            string[] strings = new string[rows.Length];
            for (int i = 0; i < strings.Length; i++)
            {
                bool hasFirst = false;
                bool hasMiddle = false;

                strings[i] = "";
                if (rows[i].ItemArray.GetValue(1).ToString() != "")
                {
                    hasFirst = true;
                    strings[i] += rows[i].ItemArray.GetValue(1).ToString();
                }
                if (rows[i].ItemArray.GetValue(2).ToString() != "")
                {
                    hasMiddle = true;
                    if (hasFirst)
                    {
                        strings[i] += " ";
                    }
                    strings[i] += rows[i].ItemArray.GetValue(2).ToString();
                }
                if (rows[i].ItemArray.GetValue(3).ToString() != "")
                {
                    if ((hasFirst && !hasMiddle) || (hasMiddle))
                    {
                        strings[i] += " ";
                    }
                    strings[i] += rows[i].ItemArray.GetValue(3).ToString();
                }
                if (rows[i].ItemArray.GetValue(4).ToString() != "")
                {
                    strings[i] += " " + rows[i].ItemArray.GetValue(4).ToString();
                }
            }

           // int choice;
            Form2 form2 = new Form2(strings);
            if (form2.ShowDialog(this) == DialogResult.OK)
            {
                primaryKey = rows[form2.choice].ItemArray.GetValue(0).ToString();
               // choice = form2.choice;
                fillTextBoxes(rows[form2.choice]);
                currentRow = rows[form2.choice];
                recordShown = true;
            }
        }            
        else
        {
            primaryKey = rows[0].ItemArray.GetValue(0).ToString();
            currentRow = rows[0];
            fillTextBoxes(rows[0]);
            recordShown = true;
        }
    }

    private void btnAdd_Click(object sender, EventArgs e)
    {
        con.Open();

        DataRow row = dataset.Tables["Contacts"].NewRow();
        row[1] = tbFirstName.Text;
        row[2] = tbMiddleName.Text;
        row[3] = tbLastName.Text;
        row[4] = tbSuffix.Text;
        row[5] = tbHomePhone.Text;
        row[6] = tbCellPhone.Text;
        row[7] = tbOtherPhone.Text;
        row[8] = tbStreetAddress.Text;
        row[9] = tbCityAndState.Text;
        row[10] = tbCountry.Text;
        row[11] = tbEmail.Text;
        currentRow = row;

        dataset.Tables["Contacts"].Rows.Add(row);
        dAdapter.Update(dataset, "Contacts");
        recordShown = true;

        con.Close();
    }

    private void btnUpdate_Click(object sender, EventArgs e)
    {
        if (recordShown)
        {
            con.Open();

            currentRow[1] = tbFirstName.Text;
            currentRow[2] = tbMiddleName.Text;
            currentRow[3] = tbLastName.Text;
            currentRow[4] = tbSuffix.Text;
            currentRow[5] = tbHomePhone.Text;
            currentRow[6] = tbCellPhone.Text;
            currentRow[7] = tbOtherPhone.Text;
            currentRow[8] = tbStreetAddress.Text;
            currentRow[9] = tbCityAndState.Text;
            currentRow[10] = tbCountry.Text;
            currentRow[11] = tbEmail.Text;

            dAdapter.Update(dataset, "Contacts");

            con.Close();
        }
        else
        {
            MessageBox.Show("Please locate/add a record first.");
        }
    }

    private void btnDelete_Click(object sender, EventArgs e)
    {
        con.Open();

        currentRow.Delete();
        dAdapter.Update(dataset, "Contacts");
        clearTextBoxes();
        recordShown = false;

        con.Close();
    }
}
}

谢谢!

2 个答案:

答案 0 :(得分:2)

这是一个解释,但我不确定它是否正是您所看到的:

http://blogs.msdn.com/b/spike/archive/2010/04/07/concurrency-violation-the-updatecommand-affected-0-of-the-expected-1-records.aspx

这可能会更加正常,如果是这样,则指出在声明cmdBuilder之后应该出现的一些缺失行:

dAdapter.UpdateCommand = cmdBuilder.GetUpdateCommand();
dAdapter.InsertCommand = cmdBuilder.GetInsertCommand();
dAdapter.DeleteCommand = cmdBuilder.GetDeleteCommand();

http://www.codeguru.com/forum/archive/index.php/t-337168.html

此外,您可能需要致电:

dAdapter.Fill(dataset, "Contacts");
对于所有三个操作(插入,更新和删除)的con.Close()之前的




在一个不相关的说明中,您可以通过将“fillTextBoxes(int row)”方法更改为以下来减少重复代码:

private void fillTextBoxes(int row)
{
  DataRow dr = dataset.Tables["Contacts"].Rows[row];
  fillTextBoxes(dr);
}

答案 1 :(得分:1)

有些事情,看起来你在调用update时没有将它传回你的标识列的ID。在进行更新时是不是需要知道ID?

除了srutzky关于fillTextBoxes中冗余代码的注释之外,您还可以考虑不按顺序值引用列,而是通过实际列名引用它们。如果要向数据库添加列,则会破坏所有正在执行以下操作的代码:

tbLastName.Text = dr.ItemArray.GetValue(3).ToString();

相反,您可能会执行以下操作:

tbLastName.Text = dr.ItemArray.GetValue("LastName").ToString();

我不知道GetValue是否将列名作为参数,但我确信它是这样的。