简体   繁体   English

C# Access数据库插入后不更新数据

[英]C# Access database doesn't update data after inserting

I'm working on a school project and I ran into a problem.我正在做一个学校项目,我遇到了一个问题。 When I insert/update/delete data from the database, the data isn't shown before I restart the application.当我从数据库中插入/更新/删除数据时,在我重新启动应用程序之前不会显示数据。 I have to close the app and open it again for it to show changes.我必须关闭应用程序并再次打开它才能显示更改。

When I change the OleDbConnection string (when I change the source), data is updated but it's only shown until I close the app, when I close the app I lose all the new data.当我更改OleDbConnection字符串时(当我更改源时),数据会更新,但它只会在我关闭应用程序之前显示,当我关闭应用程序时,我会丢失所有新数据。 Data from the database is shown in dataGridView .数据库中的数据显示在dataGridView中。 When I choose the data source for dataGridView the code line is written automatically in form load event with that code I can update data when the source is changed to the file that doesn't save data.当我为dataGridView选择数据源时,代码行会使用该代码自动写入表单加载事件中,当源更改为不保存数据的文件时,我可以更新数据。

I'm wondering if there are any other ways to automatically refresh(or with a button) dataGridView after new data has been added.我想知道添加新数据后是否还有其他方法可以自动刷新(或使用按钮) dataGridView I'm using VS C# 2008 express edition because that is the one we use in school.我正在使用VS C# 2008 速成版,因为这是我们在学校使用的那个。

Here's the code for the insert button:下面是插入按钮的代码:

 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);
    }

Here is the connection string, this is the way I've been taught in school.这是连接字符串,这是我在学校被教导的方式。

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");

When I change the connection string to go to the bin/debug folder it updates automatically but doesn't save data.当我将连接字符串更改为 go 到 bin/debug 文件夹时,它会自动更新但不保存数据。

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

OK the reason you're hitting problems and different behaviors when you change the connection string is one of:好的,您在更改连接字符串时遇到问题和不同行为的原因是以下之一:

  • There are two databases on disk, and you're looking in the wrong one磁盘上有两个数据库,你找错了一个
  • You're doing your data access in the wrong way您以错误的方式进行数据访问

You're hitting both of these.你正在打这两个。 First, i'll explain the first one.首先,我将解释第一个。

When you added the access database to your project (however you did it, there are a few ways) this dialog box (or similar - this is vs 2019) probably appeared当您将 access 数据库添加到您的项目中时(无论如何,有几种方法)这个对话框(或类似的 - 这是 vs 2019)可能会出现

X

It is long and boring, and tells people a lot of stuff they probably don't understand so they just hit Yes and forget about it.它又长又无聊,并且告诉人们很多他们可能不理解的东西,所以他们只是点击“是”然后忘记它。 Later they will be very confused when trying to save data后来他们在尝试保存数据时会很困惑

This box is basically saying "i'll copy the db into your project folder, but remember that every time you press play, it will be copied again to the BIN folder and your running program will modify the database in the bin folder , not the db in the project folder, and not the db from your desktop (or wherever)"这个框基本上是在说“我将把数据库复制到你的项目文件夹中,但请记住,每次按下播放时,它都会再次复制到 BIN 文件夹,并且你正在运行的程序将修改bin 文件夹中的数据库,而不是项目文件夹中的 db,而不是桌面(或任何地方)中的 db”

Later the dev runs the program, saves some data, looks in Access, doesn't find it.后来开发人员运行程序,保存了一些数据,在 Access 中查找,没有找到。 Or they run the program again and wonder "where is my data gone that I just saved".或者他们再次运行程序并想知道“我刚刚保存的数据到哪里去了”。

"Every time you run the program the db from the project folder is copied to the bin folder" “每次运行程序时,项目文件夹中的 db 都会复制到 bin 文件夹中”

It means the database your program saves its data in will be wiped and replaced every time you build your project in visual studio.这意味着每次在 Visual Studio 中构建项目时,程序保存其数据的数据库都会被擦除和替换。 It doesn't affect a live app (live apps don't build themselves every time you run them), just one you run in VS它不会影响实时应用程序(实时应用程序不会在每次运行时自行构建),只会影响您在 VS 中运行的应用程序

And if you look in any db other than the one in BIN folder, you wont find the data, because you're looking in the wrong one如果您查看 BIN 文件夹中的数据库以外的任何数据库,您将找不到数据,因为您正在查找错误的数据库

I suggest you find your DB in solution explorer, right click it, choose Properties and change "Copy to output" to "Copy If Newer".我建议您在解决方案资源管理器中找到您的数据库,右键单击它,选择属性并将“复制到输出”更改为“如果较新则复制”。 This way VS will only replace the db in the bin folder when you've made a change to the db in the project folder (ie added a new table) - this is more like what you want to do, usually这样VS只会在您对项目文件夹中的数据库进行更改(即添加一个新表)时替换bin文件夹中的数据库 - 这更像是您想要做的,通常


Now I commented that you're doing your data access incorrectly:现在我评论说您的数据访问不正确:

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);
}

There is absolutely no need to make an OleDbCommand in your app, at all.完全没有必要在您的应用程序中创建 OleDbCommand。 VS writes all that code for you, in a DataSet (HotelDataSet). VS 在数据集 (HotelDataSet) 中为您编写所有代码。 A TableAdapter contains an OleDbCommand inside it; TableAdapter 内部包含一个 OleDbCommand; several in fact.事实上有几个。 A TableAdapter is a device that downloads data from your db into your dataset, and is also responsible for saving it back to the db when there are changes (new records, changed records and deleted records). TableAdapter 是一种将数据从您的数据库下载到您的数据集中的设备,并且还负责在发生更改(新记录、更改的记录和删除的记录)时将其保存回数据库。

All that magic happens in tableadapter.Update(..) - Update doesn't just run updates.所有这些魔法都发生在tableadapter.Update(..) - 更新不只是运行更新。 It runs inserts and deletes too - when you download data into a dataset it ends up stored inside a datarow, inside a datatable.它也运行插入和删除- 当您将数据下载到数据集中时,它最终存储在数据行中,在数据表中。 This is very similar to databases.这与数据库非常相似。 DataRows track what your user does - if there is a new row made and added to a datatable it has a RowState of Added. DataRows 跟踪您的用户所做的事情 - 如果创建了新行并将其添加到数据表中,则它的 RowState 为已添加。 If you change the data in an existing row it has a state of Modified.如果您更改现有行中的数据,则它的 state 为已修改。 If you remove the row from the datatable it will be marked as deleted.如果您从数据表中删除该行,它将被标记为已删除。 When you call tableadapter.Update(theDatatable) different SQL INSERT/UPDATE/DELETE will be made to save whatever you did to your Added/Modified/Deleted rows respectively.当您调用tableadapter.Update(theDatatable)不同的 SQL INSERT/UPDATE/DELETE 将分别保存您对添加/修改/删除行所做的任何事情。 After you save, a row changes to Unchanged state.保存后,一行更改为 Unchanged state。 If you edit it again, it becomes Modified again, so it will be saved again when you call Update如果再次编辑它,它会再次变为Modified,所以调用Update时会再次保存

Therefore if you want to insert a row into the DB, you should Add it to the datatable, then Update to save it.因此,如果您想在数据库中插入一行,您应该将其添加到数据表中,然后更新以保存它。 If the datatable is being viewed by eg a DataGridView, then the grid will see the change automatically and show it when you add it如果数据表正在由例如 DataGridView 查看,则网格将自动查看更改并在添加时显示它

It probably goes like this:大概是这样的:

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

Now that row will appear in a datagridview.现在该行将出现在 datagridview 中。 It is not in the database yet it is only in the local datatable, which is like a cache/temporary data storage in the client only.它不在数据库中,但仅在本地数据表中,这就像仅在客户端中的缓存/临时数据存储。 You must save it to make it go into the DB.您必须保存它以使其 go 进入数据库。 This saves the data:这将保存数据:

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

You claimed that is written in the Form Load;您声称是在表单加载中写的; it isn't.不是。 The thing in the form load is a call to Fill , NOT Update .表单加载中的内容是调用Fill ,而不是Update Fill is for loading.填充用于加载。 Update is for saving.更新是为了保存。

The default behavior of windows forms using datasets when you add bound grids to forms is to call Fill on the form load, to download all data out of the database so you have something to look at.当您将绑定网格添加到 forms 时,windows forms 使用数据集的默认行为是在表单加载时调用 Fill,以从数据库中下载所有数据,以便您查看。 It doesn't call update in the form load because the form is new;它不会在表单加载中调用更新,因为表单是新的; there is nothing to update.没有什么可更新的。 Any time you want to download data from the db you call Fill.任何时候你想从你调用 Fill 的数据库中下载数据。

This is why you hit your second problem when you changed your connection string to point to some different DB not in the BIN folder, and then you used an OleDbCommand to insert data into the db - it only showed up when you reloaded the program because your Form Load calls Fill, which is how your new data gets from the db to the program.这就是为什么当您将连接字符串更改为指向不在 BIN 文件夹中的其他数据库时遇到第二个问题,然后您使用 OleDbCommand 将数据插入数据库 - 它仅在您重新加载程序时出现,因为您的表单加载调用填充,这是您的新数据从数据库获取到程序的方式。 Because you used an OleDbCommand to do a direct insert you went completely outside all the data handling built into your program, and inserted to the DB directly.因为您使用 OleDbCommand 进行直接插入,所以您完全超出了程序中内置的所有数据处理,并直接插入到数据库中。 Your program never knew the data was written;您的程序永远不知道数据已写入; you never stored the data in anything in your program that was wired up to the UI您从未将数据存储在程序中连接到 UI 的任何内容中

Of course, if you only ever load data once upon loading the form then you will have to restart your program to load the data.当然,如果您只在加载表单时加载一次数据,那么您将不得不重新启动程序来加载数据。 The idea is that you can call Fill at other times too;这个想法是您也可以在其他时间调用 Fill; not just at form load.不只是在表单加载。 I'll talk about this later我稍后会谈到这个

Don't use OleDbCommands to directly insert data in you're working with tableadapters;不要使用 OleDbCommands直接在您使用 tableadapter 的过程中插入数据; it will cause a world of confusion and is a bad solution.这将导致混乱的世界,并且是一个糟糕的解决方案。 Use tableadapters how they were intended;按预期使用表格适配器; load your new data into a datatable (inside a dataset) using a tableadapter and later save the table using the tableadapter.使用 tableadapter 将新数据加载到数据表(在数据集内),然后使用 tableadapter 保存表。 If the tableadapter doesn't load/save how you want you can change that:如果 tableadapter 没有加载/保存您想要的方式,您可以更改它:


Now, you actually probably want to get rid of this line in form load that loads the entire db table into the local dataet, because downloading all data rarely what we do.现在,您实际上可能希望摆脱表单加载中将整个 db 表加载到本地数据集的这一行,因为我们很少下载所有数据。 Loading all million stock prices into the app is a bad idea;将所有百万股票价格加载到应用程序中是一个坏主意; just load the ones you want只需加载您想要的

To give an example of this, open the HotelDataSet file in your project, find some tableadapter, like SobeTableAdapter, right click it, choose Add>>Query.举个例子,打开项目中的 HotelDataSet 文件,找到一些 tableadapter,比如 SobeTableAdapter,右键单击它,选择 Add>>Query。 Choose "select that returns rows", put a query like SELECT * FROM Sobe WHERE Broj_Sobe LIKE?选择“选择返回行”,输入一个查询,如SELECT * FROM Sobe WHERE Broj_Sobe LIKE? , call it FillByBrojSobe, finish the wizard. ,称之为 FillByBrojSobe,完成向导。

Now in your code you can search like:现在在您的代码中,您可以搜索:

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

Or或者

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

The records are filled into HotelDataSet.Sobe .记录被填充到HotelDataSet.Sobe中。 Any datagridview binded to this (ie a line of code like this will bind the grid to the data: datagridViewSobe.DataSource = HotelDataSet.Sobe - this is usually done in the forms designer so you don't see a line of code like this in your project*) will refresh automatically to show the data you filled.任何与此绑定的 datagridview(即这样的一行代码会将网格绑定到数据: datagridViewSobe.DataSource = HotelDataSet.Sobe - 这通常在 forms 设计器中完成,因此您在您的项目*) 将自动刷新以显示您填写的数据。 Edit the data in the grid, and save it by wiring up some other button that calls tableadapter.Update(..) .编辑网格中的数据,并通过连接其他一些调用tableadapter.Update(..)的按钮来保存它。 You even normally get a cute one by default when you drop a grid onto the form (out of the Data Sources window), embedded in a toolbar called the BindingNavigator当您将网格拖放到表单(数据源窗口之外)时,您甚至通常会默认获得一个可爱的网格,嵌入在名为 BindingNavigator 的工具栏中

Remember;记住; stay away from OleDbCommand;远离 OleDbCommand; you absolutely don't need it, ever.你绝对不需要它,永远。 You can add all the queries you'll ever need to a tableadapter using the wizard like I showed above.您可以使用上面显示的向导将您需要的所有查询添加到 tableadapter。 It's faster and more secure;它更快、更安全; the query you wrote in the oledbcommand was horribly at risk of SQL injection hacking and writing SQLs like that could one day get you fired.您在 oledbcommand 中编写的查询极有可能遭受 SQL 注入黑客攻击和编写这样的 SQL 有一天可能会让您被解雇。 Writing queries into the tableadapter wizard ensures that they will be built into your tableadapter in a secure way that is not at risk of hacking将查询写入 tableadapter 向导可确保它们以安全的方式内置到您的 tableadapter 中,不会受到黑客攻击

One day you'll probably move on from datasets and tableadapters and shift to entity framework, but this is a good intro, just a bit of a steep learning curve.有一天,您可能会从数据集和表格适配器转向实体框架,但这是一个很好的介绍,只是有点陡峭的学习曲线。

Oh, and install VS2019 even if only on your personal computer if available;哦,安装 VS2019,即使只有在您的个人计算机上(如果有); 2008 is a horrific experience in comparison (and I don't think it can even work with .NET 4..)相比之下,2008 年是一次可怕的经历(我认为它甚至不能与 .NET 4 一起使用。)

* actually what the form designer usually does is bind a bindingsource to the datatable and then binds the grid to the bindingsource, but i'll ignore that for now *实际上,表单设计器通常所做的是将绑定源绑定到数据表,然后将网格绑定到绑定源,但我现在将忽略它

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM