Как избавиться от проблемы параллелизма с помощью операторов обновления с автоинкрементным ключом? - PullRequest
3 голосов
/ 22 января 2011

Я столкнулся со следующим сообщением об ошибке во время выполнения программы базы данных Sql / Visual C # моего новичка:

Нарушение параллелизма: команда UpdateCommand затронула 0 из ожидаемых 1 записей.

Я провел несколько поисков по этой проблеме и видел несколько тем об этом, но их мне недостаточно, чтобы решить эту проблему. Я заметил, что люди говорят о том, как часто это происходит при использовании автоинкрементного первичного ключа. Это случай в этой программе. Также нет многопоточности или чего-то подобного, что я кодирую в эту программу. Поэтому я думаю, что автоинкремент, возможно, является единственной проблемой.

При этом, как заставить команду update работать, несмотря на автоинкремент? Я едва могу встать на ноги, когда дело доходит до программирования баз данных, поэтому, пожалуйста, будьте внимательны, если не возражаете. Кроме того, я использую команду через объект SqlCommandBuilder. Я установил для этого объекта новый SqlCommandBuilder (DataAdapter), и я не сделал с ним ничего особенного.

Спасибо.


Это второе редактирование. Первый ниже.

Из-за моей неопытности в программировании баз данных я не могу сказать это наверняка. Однако у меня есть веские основания полагать, что проблема, с которой я сталкиваюсь, связана с тем, что новые строки не добавляются в базу данных полностью, пока программа не завершится. Я не понимаю, почему они ждут до завершения программы, чтобы сделать это, или если они ждут до тех пор, просто что именно из-за завершения программы заставляет их внезапно быть полностью сохраненными. Однако я забыл упомянуть, что эта ошибка возникает только в строках, которые я добавил во время выполнения этой конкретной программы. Если строка уже была добавлена ​​при предыдущем выполнении или с помощью уже существующих табличных данных, все в порядке. Я получаю ту же ошибку с методом удаления, и это также происходит только с новыми строками.

Как мне полностью сохранить эти строки во всем, чтобы этого не произошло? Как насчет завершения программы вызывает полное сохранение этих строк? Спасибо!


По запросу я оставил здесь два фрагмента кода. Первым будет метод, в котором возникает проблема. Следующий будет включать весь класс. Во всей программе всего два класса, и другой класс не кажется мне важным в этом конкретном вопросе.

    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 ]

2 голосов
/ 23 января 2011

Вот одно объяснение, но я не уверен, что это именно то, что вы видите:

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 голос
/ 23 января 2011

Пара вещей, похоже, что вы не передаете его обратно идентификатору вашего столбца идентификации при вызове update.Разве ему не нужно знать идентификатор при выполнении обновления?

В дополнение к комментарию, который srutzky сделал относительно избыточного кода в fillTextBoxes, вы можете также рассмотреть возможность не ссылаться на ваши столбцы по порядковому значению и вместо этого ссылаться на нихпо их фактическому имени столбца.Если бы вы добавили столбец в вашу БД, это повредило бы весь ваш код, выполняющий такие вещи, как:

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

Вместо этого вы могли бы сделать что-то вроде:

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

Я не знаю, принимает ли GetValue имя столбца в качестве параметра, но я уверен, что это что-то вроде этого.

...