【问题标题】:C# Access database doesn't update data after insertingC# Access 数据库在插入后不更新数据
【发布时间】:2021-05-04 04:37:43
【问题描述】:

我正在做一个学校项目,但遇到了问题。当我从数据库中插入/更新/删除数据时,在我重新启动应用程序之前不会显示数据。我必须关闭应用并再次打开它才能显示更改。

当我更改OleDbConnection 字符串时(当我更改源时),数据会更新,但它只会在我关闭应用程序之前显示,当我关闭应用程序时,我会丢失所有新数据。来自数据库的数据显示在dataGridView 中。当我为dataGridView 选择数据源时,代码行会自动写入表单加载事件中,并使用该代码在源更改为不保存数据的文件时更新数据。

我想知道添加新数据后是否还有其他方法可以自动刷新(或使用按钮)dataGridView。我正在使用 VS C# 2008 速成版,因为这是我们在学校使用的版本。

插入按钮的代码如下:

 private void buttonInsert_Click(object sender, EventArgs e)
    {

        konekcija.Open();
        OleDbCommand komanda = konekcija.CreateCommand();
        komanda.CommandType = CommandType.Text;
        komanda.CommandText = ("Insert into Sobe(Broj_sobe,Tip_sobe,Telefon,Stanje)values('"
            + textBoxBrSobe.Text + "','" + textBox2.Text +"','" + textBoxTelefon.Text + "','" + textBox1.Text + "')");
        komanda.ExecuteNonQuery();
        
        konekcija.Close();
        MessageBox.Show("Uspjeli ste");
//this is written automatically in form load event
        this.sobeTableAdapter1.Update(this.hotelDataSet1.Sobe);
    }

这是连接字符串,这是我在学校被教导的方式。

OleDbConnection konekcija = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:/Users/Pupo/Desktop/Hotel/Hotel/Hotel/Hotel.mdb;Persist Security Info=False");

当我更改连接字符串以转到 bin/debug 文件夹时,它会自动更新但不保存数据。

OleDbConnection konekcija = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Hotel.mdb;Persist Security Info=False");

【问题讨论】:

  • 一个适配器有四个命令 1) 选择 2) 删除) 3) 更新 4) 插入。要使更新方法起作用,您需要所有找到的命令。 commandBuilder 采用 Select 命令并自动构建其他三个。请参阅:docs.microsoft.com/en-us/dotnet/api/…
  • 当你在 bin/debug 中有 db 文件时,它可能会在每次编译时被覆盖
  • 顺便说一句,通过在你的命令字符串中包含用户文本,你会遇到 sql 注入问题。甚至 Access 也可以使用参数(仅位置,但仍然...)
  • 还有; VS 2008,如.. 13 年前?你的学校是故意妨碍你的教育吗?????? 13 年发生了这么多事情,就计算而言,这几乎是一生前的事了。我无法合理地看出你的学校可能有什么借口坚持使用如此古老的版本 - 有 Visual Studio 2019 的免费版本和如果您需要的东西不存在,Microsoft 的学生定价确实物有所值
  • 谢谢大家,我成功了。我设法通过制作一个执行 SELECT 命令的按钮来解决问题。不是最好的解决方案,但可以解决问题。

标签: c#


【解决方案1】:

好的,您在更改连接字符串时遇到问题和不同行为的原因是:

  • 磁盘上有两个数据库,您找错了一个
  • 您以错误的方式访问数据

这两个你都打了。首先,我将解释第一个。

当您将 access 数据库添加到您的项目时(无论如何,有几种方法)这个对话框(或类似的 - 这是 vs 2019)可能会出现

它又长又无聊,而且会告诉人们很多他们可能不理解的东西,所以他们只是点击“是”然后忘记它。以后他们在尝试保存数据时会很困惑

这个框基本上是在说“我将把 db 复制到你的项目文件夹中,但请记住,每次按下播放时,它都会再次复制到 BIN 文件夹,而你正在运行的程序将修改 bin 文件夹中的数据库,而不是项目文件夹中的 db,而不是桌面(或任何地方)中的 db"

稍后开发人员运行程序,保存一些数据,在 Access 中查找,没有找到。或者他们再次运行程序并想知道“我刚刚保存的数据到哪里去了”。

"每次运行程序时,项目文件夹中的 db 都会复制到 bin 文件夹中"

这意味着每次在 Visual Studio 中构建项目时,程序保存数据的数据库都会被擦除和替换。它不会影响实时应用(实时应用不会在每次运行时自行构建),只会影响您在 VS 中运行的一个

如果您查看 BIN 文件夹中的数据库以外的任何数据库,您将找不到数据,因为您查看的是错误的数据库

我建议您在解决方案资源管理器中找到您的数据库,右键单击它,选择属性并将“复制到输出”更改为“如果较新则复制”。这样,VS 只会在您对项目文件夹中的 db 进行更改(即添加一个新表)时替换 bin 文件夹中的 db - 这更像是您想要做的,通常


现在我评论说您的数据访问不正确:

private void buttonInsert_Click(object sender, EventArgs e)
{

    konekcija.Open();
    OleDbCommand komanda = konekcija.CreateCommand();
    komanda.CommandType = CommandType.Text;
    komanda.CommandText = ("Insert into Sobe(Broj_sobe,Tip_sobe,Telefon,Stanje)values('"
        + textBoxBrSobe.Text + "','" + textBox2.Text +"','" + textBoxTelefon.Text + "','" + textBox1.Text + "')");
    komanda.ExecuteNonQuery();
    
    konekcija.Close();
    MessageBox.Show("Uspjeli ste");
    //this is written automatically in form load event
    this.sobeTableAdapter1.Update(this.hotelDataSet1.Sobe);
}

完全没有必要在您的应用中创建 OleDbCommand。 VS 在数据集 (HotelDataSet) 中为您编写所有代码。 TableAdapter 包含一个 OleDbCommand 在它里面;事实上有几个。 TableAdapter 是一种将数据从您的数据库下载到您的数据集中的设备,并且还负责在发生更改(新记录、更改的记录和删除的记录)时将其保存回数据库。

所有这些魔法都发生在tableadapter.Update(..) - 更新不只是运行更新。它也运行插入和删除 - 当您将数据下载到数据集中时,它最终存储在数据行中,在数据表中。这与数据库非常相似。 DataRows 跟踪您的用户所做的事情 - 如果创建了新行并将其添加到数据表中,则它的 RowState 为已添加。如果您更改现有行中的数据,则其状态为已修改。如果您从数据表中删除该行,它将被标记为已删除。当您调用 tableadapter.Update(theDatatable) 时,将进行不同的 SQL INSERT/UPDATE/DELETE 以分别保存您对添加/修改/删除行所做的任何事情。保存后,一行更改为未更改状态。如果再次编辑它,它会再次变为Modified,所以调用Update时会再次保存

因此,如果你想在数据库中插入一行,你应该将它添加到数据表中,然后更新以保存它。如果数据表正在由例如 DataGridView 查看,那么网格将自动看到更改并在添加时显示它

大概是这样的:

//put this in a button click
hotelDataSet1.Sobe.AddSobeRow(textBoxBrSobe.Text, textBox2.Text, textBoxTelefon.Text, textBox1.Text);

现在该行将出现在 datagridview 中。 它还没有在数据库中它只是在本地数据表中,这就像一个缓存/临时数据存储在客户端中。您必须保存它以使其进入数据库。这会保存数据:

this.sobeTableAdapter1.Update(this.hotelDataSet1.Sobe);

您声称是在表单加载中写入的;不是。表单加载中的内容是调用Fill,而不是Update。填充用于加载。更新是为了保存。

当您将绑定网格添加到表单时,使用数据集的 Windows 表单的默认行为是在表单加载时调用 Fill,从数据库中下载所有数据,以便您可以查看一些内容。它不会在表单加载中调用更新,因为表单是新的;没有什么可更新的。任何时候你想从你调用 Fill 的数据库中下载数据。

这就是为什么当您将连接字符串更改为指向不在 BIN 文件夹中的其他数据库时遇到第二个问题的原因,然后您使用 OleDbCommand 将数据插入数据库 - 它仅在您重新加载时出现程序,因为您的表单加载调用填充,这是您的新数据从数据库获取到程序的方式。因为您使用 OleDbCommand 进行直接插入,所以您完全超出了程序中内置的所有数据处理,并直接插入到数据库中。您的程序永远不知道数据已写入;您从未将数据存储在程序中连接到 UI 的任何内容中

当然,如果您在加载表单时只加载一次数据,那么您将不得不重新启动程序来加载数据。这个想法是您也可以在其他时间调用 Fill;不只是在表单加载。这个我以后再说

不要使用 OleDbCommands 在您正在使用 tableadapter 的过程中直接插入数据;这将导致混乱的世界,并且是一个糟糕的解决方案。按预期使用表格适配器;使用 tableadapter 将新数据加载到数据表(在数据集内),然后使用 tableadapter 保存表。如果 tableadapter 没有加载/保存您想要的方式,您可以更改:


现在,您实际上可能希望删除表单加载中将整个 db 表加载到本地数据集的这一行,因为下载所有数据很少像我们所做的那样。将所有百万股票价格加载到应用程序中是一个坏主意;只需加载你想要的

举个例子,在你的项目中打开HotelDataSet文件,找到一些tableadapter,比如SobeTableAdapter,右击它,选择Add>>Query。选择“选择返回行”,输入类似SELECT * FROM Sobe WHERE Broj_Sobe LIKE ?的查询,命名为FillByBrojSobe,完成向导。

现在您可以在您的代码中搜索:

sobeTableAdapter1.FillByBrojSobe(this.HotelDataSet.Sobe, "ABC"); // fill only records with a Broj_Sobe = "ABC"

或者

sobeTableAdapter1.FillByBrojSobe(this.HotelDataSet.Sobe, "DEF%"); // fill only records with a Broj_Sobe starting with "DEF"

记录填入HotelDataSet.Sobe。任何绑定到此的 datagridview(即这样的一行代码会将网格绑定到数据:datagridViewSobe.DataSource = HotelDataSet.Sobe - 这通常在表单设计器中完成,因此您在项目中看不到这样的代码行*)将自动刷新以显示您填写的数据。编辑网格中的数据,并通过连接其他一些调用tableadapter.Update(..) 的按钮来保存它。当您将网格拖放到表单上(从“数据源”窗口外)时,您甚至通常会默认得到一个可爱的网格,嵌入在名为 BindingNavigator 的工具栏中

记住;远离 OleDbCommand;你绝对不需要它,永远。您可以使用上面显示的向导将您需要的所有查询添加到 tableadapter。它更快、更安全;您在 oledb 命令中编写的查询极有可能遭受 SQL 注入黑客攻击,并且编写这样的 SQL 有一天可能会让您被解雇。将查询写入 tableadapter 向导可确保它们以安全的方式内置到您的 tableadapter 中,不会有被黑客入侵的风险

有一天你可能会从数据集和表格适配器转向实体框架,但这是一个很好的介绍,只是有点陡峭的学习曲线。

哦,安装 VS2019,即使只在您的个人计算机上(如果有);相比之下,2008 年是一次可怕的经历(我认为它甚至不能与 .NET 4 一起使用……)

*实际上表单设计者通常所做的是将绑定源绑定到数据表,然后将网格绑定到绑定源,但我现在将忽略它

【讨论】:

  • 非常感谢。我将尝试从我的代码中完全删除 OleDbCommands 并尝试这样做。我什至没有注意到我在那一行写了更新而不是填充,每隔一次我调用那行代码它就是填充命令。我一完成学业(10-15 天)就会安装 VS2019。我的电脑实际上挤满了 10 年以上的程序。再次非常感谢你,这是一个很大的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多