我对Visual C#完全陌生。我正在尝试创建一个具有数据库的程序来注册产品和客户。我只是遵循了这两个walktrhoughs:

Creating a Local Database File in Visual Studio

Connecting to Data in a Local Database File (Windows Forms)

然后我在解决方案上创建了3个表单:

Form1:启动屏幕,几秒钟后隐藏并打开Form2。

Form2:具有4个面板,[A]为产品添加新的和编辑的寄存​​器(我将表拖放到“详细信息”模式),[B]具有DataGridView的单元格配置为只读= true。其他2个面板对于客户来说是相同的。

Form3:双击DataGridView中的单元格时打开的对话框。此对话框显示产品数据,其中只有几个字段可编辑。

我的问题:

如果在Form2 [A]上编辑一个字段并将其保存,则可以在DataGridView [B]和Form3上看到更改。

如果我在Form3上编辑一个字段并将其保存,然后关闭对话框,则[A]面板和[B]面板上的Form2都没有变化。但是,当我再次打开Form3时,已编辑的数据就在那里。并且,如果我在[A]上编辑了在Form3上编辑的相同字段并尝试保存,则会出现以下错误:


  LojaEstiloDesign20150906.exe中发生了类型为'System.Data.DBConcurrencyException'的未处理异常
  
  其他信息:并发冲突:UpdateCommand影响了预期的1条记录中的0条。”




这似乎是一个非常基本的问题,但是我不知道如何解决。我已经尝试了很多东西,但是都没有用。
任何帮助将不胜感激。

表格2:

namespace LojaEstiloDesign20150906
{
public partial class frm_Menu : Form
{
    public frm_Menu()
    {
        InitializeComponent();
    }

    private void CadProdutosToolStripMenuItem_Click(object sender, EventArgs e)
    {
        panel_CadastroProdutos.Visible = true;
        panel_CadastroProdutos.Dock = DockStyle.Fill;

        panel_CadastroClientes.Visible = false;
        panel_ConsultaClientes.Visible = false;
        panel_ConsultaProdutos.Visible = false;
    }

    private void CadClientesToolStripMenuItem_Click(object sender, EventArgs e)
    {
        panel_CadastroClientes.Visible = true;
        panel_CadastroClientes.Dock = DockStyle.Fill;

        panel_CadastroProdutos.Visible = false;
        panel_ConsultaClientes.Visible = false;
        panel_ConsultaProdutos.Visible = false;
    }

    private void ConProdutosToolStripMenuItem1_Click(object sender, EventArgs e)
    {
        panel_ConsultaProdutos.Visible = true;
        panel_ConsultaProdutos.Dock = DockStyle.Fill;

        panel_CadastroClientes.Visible = false;
        panel_ConsultaClientes.Visible = false;
        panel_CadastroProdutos.Visible = false;
    }

    private void ConClientesToolStripMenuItem1_Click(object sender, EventArgs e)
    {
        panel_ConsultaClientes.Visible = true;
        panel_ConsultaClientes.Dock = DockStyle.Fill;

        panel_CadastroClientes.Visible = false;
        panel_ConsultaProdutos.Visible = false;
        panel_CadastroProdutos.Visible = false;
    }

    private void frm_Menu_FormClosing(object sender, FormClosingEventArgs e)
    {
        Application.Exit();
    }

    private void produtosBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
        this.Validate();
        this.produtosBindingSource.EndEdit();
        this.tableAdapterManager.UpdateAll(this.lojaEstiloDataSet);

    }

    private void frm_Menu_Load(object sender, EventArgs e)
    {
        // TODO: This line of code loads data into the 'lojaEstiloDataSet.Clientes' table. You can move, or remove it, as needed.
        this.clientesTableAdapter.Fill(this.lojaEstiloDataSet.Clientes);
        // TODO: This line of code loads data into the 'lojaEstiloDataSet.Produtos' table. You can move, or remove it, as needed.
        this.produtosTableAdapter.Fill(this.lojaEstiloDataSet.Produtos);
    }

    private void produtosDataGridView_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
    {
        frm_FichaProdutos frm3 = new frm_FichaProdutos();
        frm3.Show();
    }

    private void toolStripButton6_Click(object sender, EventArgs e)
    {
        this.Validate();
        this.clientesBindingSource.EndEdit();
        this.tableAdapterManager.UpdateAll(this.lojaEstiloDataSet);
    }
}
}


表格3:

namespace LojaEstiloDesign20150906
{
public partial class frm_FichaProdutos : Form
{
    public frm_FichaProdutos()
    {
        InitializeComponent();
    }


    private void frm_FichaProdutos_Load(object sender, EventArgs e)
    {
        // TODO: This line of code loads data into the 'lojaEstiloDataSet.Produtos' table. You can move, or remove it, as needed.
        this.produtosTableAdapter.Fill(this.lojaEstiloDataSet.Produtos);
        // TODO: This line of code loads data into the 'lojaEstiloDataSet.Produtos' table. You can move, or remove it, as needed.
        this.produtosTableAdapter.Fill(this.lojaEstiloDataSet.Produtos);

    }

    public void produtosBindingNavigatorSaveItem_Click_1(object sender, EventArgs e)
    {
        this.Validate();
        this.produtosBindingSource.EndEdit();
        this.tableAdapterManager.UpdateAll(this.lojaEstiloDataSet);

    }
}
}

最佳答案

ADO.NET默认情况下使用开放式并发。这意味着它存储数据的两个版本(原始和当前),然后,当您尝试保存对现有记录的修改时,它将原始版本与数据库中的内容进行比较,以确保它们在保存之前匹配。这样做的目的是防止两个用户都检索相同的数据并试图保存更改,而第二个保存则覆盖第一个中所做的更改。

在您的情况下,并不是两个不同的用户拥有两个不同的应用程序实例。这是同一应用程序实例中的两种形式。您正在以第一种形式检索数据,以第二种形式检索数据,从第二种形式保存更改,然后尝试从第一种形式保存更改。第一种形式的数据的原始版本与数据库中的数据不匹配,因此发生并发冲突。

关于如何进行,您有两种选择。在有效的并发冲突中,即两个不同的用户,您将捕获异常,然后决定要做什么,这很可能是再次获取数据并让用户重新编辑或合并其更改。那不是您要走的路。您应该扔掉第一个表单中的数据,然后在第二个表单关闭时再次获取它,否则首先不要两次获取相同的数据。

在第二种选择中,第一种形式可以将已经拥有的数据传递给第二种形式,而不是第二种形式获取自己的数据。因为只有一个数据副本,所以它将始终与数据库保持同步。

10-07 12:37
查看更多