Updating Microsoft Access using OleDbAdapter.Update - c#

I have been able to bind the data in my MS Access database to textboxes on a form. But when I update the data, no changes are made to the database. I made a simplified example to demonstrate my problem. The form contains only two textboxes (txtFirstName and txtLastName) and two buttons (Save and Refresh). Refresh just reloads the DataTable from the database. I load the record with ID 1 and try to update. The code is below. I know that the updates to the textboxes also update the DataTable. However, the Update function of the data adapter does nothing because no Update commands are generated by the OleDbCommandBuilder. Can anyone tell me what I am doing wrong?
Thanks so much!
// Global data
public DataTable CaseTable = new DataTable();
private OleDbCommand dbCmd;
private OleDbDataAdapter adapter;
private OleDbCommandBuilder builder;
private OleDbConnection dbConn = null;
public frmCustomer()
{
InitializeComponent();
CaseTable.Columns.Add("ID");
CaseTable.Columns.Add("FirstName");
CaseTable.Columns.Add("LastName");
this.txtFirstName.DataBindings.Add("Text", CaseTable, "FirstName"); //, true, DataSourceUpdateMode.OnPropertyChanged);
this.txtLastName.DataBindings.Add("Text", CaseTable, "LastName"); //, true, DataSourceUpdateMode.OnPropertyChanged);
}
private void frmCustomer_Load(object sender, EventArgs e)
{
dbConn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Customers.accdb");
dbCmd = new OleDbCommand("Select * From Customers Where ID = 1", dbConn);
adapter = new OleDbDataAdapter(dbCmd);
builder = new OleDbCommandBuilder(adapter);
RefreshForm();
}
private void RefreshForm()
{
CaseTable.Clear();
adapter.Fill(CaseTable);
if (CaseTable.Rows.Count < 1)
{
MessageBox.Show("Item Not Found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
private void btnSave_Click(object sender, EventArgs e)
{
if (adapter.Update(CaseTable) < 1)
MessageBox.Show("No updates");
}
private void btnRefresh_Click(object sender, EventArgs e)
{
RefreshForm();
}

I don't know why this works, but here is how I fixed my problem. At the end of RefreshForm I add the line
CaseTable.Rows[0].BeginEdit();
and at the beginning of the Save event handler I add the line
CaseTable.Rows[0].EndEdit();
Now the changes are carried back to the database. I'm not sure why none of the online references I found made reference to this.

Related

is it possible to link a text box to a database?

i'm currently working on my C# "WindowForm" Project and i want to know if it's possible to link a textbox from any form to a database and update the textbox content from time to time so the users of my application would get up to dates information of what i'm willing to post in this form (textbox).
thank you,
If you want to refresh the text in real time from a datatable, you can try SqlDependency.
The following is a simple demo.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
System.Data.SqlClient.SqlConnection conn = null;
System.Data.SqlClient.SqlCommand command = null;
// Set connection string
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder
{
DataSource = #"datasource name",
// set database
InitialCatalog = #"catalog name",
// access the database using the existing windows security certificate
IntegratedSecurity = true
};
private void Form1_Load(object sender, EventArgs e)
{
conn = new System.Data.SqlClient.SqlConnection(builder.ConnectionString);
command = conn.CreateCommand();
command.CommandText = "select text from dbo.TableText where id<>20 order by id desc ";
// Start
SqlDependency.Start(builder.ConnectionString);
// Get data
GetData();
}
private void GetData()
{
command.Notification = null;
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(sqlDependency_OnChange);
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
System.Data.DataSet ds = new DataSet();
adapter.Fill(ds, "test");
string text = ds.Tables["test"].Rows[0]["Text"].ToString();
textBox.Text = text;
}
}
void sqlDependency_OnChange(object sender, SqlNotificationEventArgs e)
{
// Because it is a child thread, you need to update the ui with the invoke method.
if (this.InvokeRequired)
{
this.Invoke(new OnChangeEventHandler(sqlDependency_OnChange), new object[] { sender, e });
}
else
{
SqlDependency dependency = (SqlDependency)sender;
dependency.OnChange -= sqlDependency_OnChange;
// After the notification, the current dependency is invalid, you need to re-get the data and set the notification.
GetData();
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
// Clear resource
SqlDependency.Stop(builder.ConnectionString);
conn.Close();
conn.Dispose();
}
}
For more info about SqlDependency, you can refer to Detecting Changes with SqlDependency.
Hope this can help you.

Show specific row on a bound form

I have a form that is bound directly with a table adapter created with the designer. I also created a list box with the key value from each record. My thought is to allow the user to click on a specific key to load the desired record in the edit screen. I can access the list entry on click, but I don't know what command to use to move to the correct row.
I am wondering if it is really worth using the bound forms like this or just do it in code, similar to how I created the list box. Any suggestions? See my code below:
public partial class Customer : Form
{
public string dbConString = "Data Source=localhost\\BALLMILL;Initial Catalog=Ballmill;Integrated Security=True";
public SqlConnection dbCon = null;
public SqlDataReader dbRdr = null;
public SqlCommand dbCommand = null;
public Customer()
{
InitializeComponent();
}
private void cUSTOMERBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
this.cUSTOMERBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.bML_WMS245GDataSet);
}
private void Customer_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'bML_WMS245GDataSet.CUSTOMER' table. You can move, or remove it, as needed.
this.cUSTOMERTableAdapter.Fill(this.bML_WMS245GDataSet.CUSTOMER);
SqlConnection dbCon = new SqlConnection(dbConString);
SqlDataReader rdrCustomers = null;
try
{
dbCon.Open();
SqlCommand sqlCustomers = new SqlCommand("SELECT CustomerCode FROM Customer", dbCon);
rdrCustomers = sqlCustomers.ExecuteReader();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString(), "Error accessing database");
return;
}
while (rdrCustomers.Read())
{
listCustomers.Items.Add(rdrCustomers["CustomerCode"].ToString());
}
}
private void listCustomers_SelectedIndexChanged(object sender, EventArgs e)
{
MessageBox.Show(listCustomers.SelectedItem.ToString(), listCustomers.SelectedIndex.ToString());
}
}
I found the answer after searching through the designer code.
cUSTOMERBindingSource.Position = listCustomers.SelectedIndex;
This automatically moves the navigator to the selected row.

Is the syntax of my Ace oledb connection string correct?

Im just starting to learn programming and i'm trying to create a windows form in c# that would allow me to view excel files through a data grid and be able to manipulate the data by using Oledb's ace connection. So Ive put this connection string in my form load but the thing is it wont populate the data grid ive set up.
Any kind of help would do and let me know if you need more info.
private void Form1_Load(object sender, EventArgs e)
{
con = new OleDbConnection(#"provider=microsoft.ace.oledb.12.0; data source=<<file path goes here>>;Extended Properties=""Excel 12.0 Xml;HDR=YES";"");
loaddata();
showdata();
}
void loaddata()
{
da = new OleDbDataAdapter("select * from [assets$]", con);
ds = new DataSet();
da.Fill(ds, "assets");
ds.Tables[0].Constraints.Add("pk_Userno", ds.Tables[0].Columns[0], true);
//this can be changed to any other item that you want to use as a primary key.)
dataGridView1.DataSource = ds.Tables[0];
}
void showdata()
{
usertxtbx.Text = ds.Tables[0].Rows[Userno][0].ToString();
brandtxtbx.Text = ds.Tables[0].Rows[Userno][1].ToString();
modeltxtbx.Text = ds.Tables[0].Rows[Userno][2].ToString();
}

Empty Data in ReportViewer in Local mode in VS2010

I am trying to show some data in form of report in Windows Form application. I am using ReportViewer in local mode for that purpose. When i run the report, it shows empty report, no errors at all!! Here is my code:
public partial class Form1 : Form
{
String thisConnectionString = "Data Source=AZEEM-NAWAZ;Initial Catalog=IEPL_Attendance_DB;Trusted_Connection = true;";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'DataSetProducts.ShowProductByCategory' table. You can move, or remove it, as needed.
//this.ShowProductByCategoryTableAdapter.Fill(this.DataSetProducts.ShowProductByCategory);
//this.reportViewer1.RefreshReport();
//reportViewer1.Visible = false;
SqlConnection thisConnection = new SqlConnection(thisConnectionString);
System.Data.DataSet thisDataSet = new System.Data.DataSet();
string cmdText = "USE [IEPL_Attendance_DB] EXEC [ShowProductByCategory]";
SqlCommand cmd = new SqlCommand(cmdText, thisConnection);
SqlDataAdapter data_ad = new SqlDataAdapter(cmd);
data_ad.Fill(thisDataSet);
/* Associate thisDataSet (now loaded with the stored
procedure result) with the ReportViewer datasource */
ReportDataSource datasource = new ReportDataSource("DataSetProducts_DataSet1", thisDataSet.Tables[0]);
reportViewer1.LocalReport.DataSources.Clear();
reportViewer1.LocalReport.DataSources.Add(datasource);
if (thisDataSet.Tables[0].Rows.Count == 0)
{
MessageBox.Show("Sorry, no products under this category!");
}
reportViewer1.LocalReport.Refresh();
//MessageBox.Show("Total Rows are: " + thisDataSet.Tables[0].Rows[0]["EmployeeName"].ToString());
}
private void reportViewer1_Load(object sender, EventArgs e)
{
}
}
Here are report.rdlc properties:
StoredProcedure "ShowProductByCategory" is returning data and i have verified by displaying rows count via MessageBox!!!
ReportDataSource datasource = new ReportDataSource("DataSetProducts_DataSet1", thisDataSet.Tables[0]);
In the above line remove the "DataSetProducts_" build it and try you will be able to see the data

Help with updating access database using Update(dataTable)

I have looked all over the place but I cant seem to get this to work.
I am trying to update an Access database from a DataGridView. The loading of the database to the grid works fine. I used the instructions described in this site.
However, to update the database based on changes made to the DataGridView, I used the command dataAdapter.Update(datatable);, but depending on the placement (next to this code) the code runs but the database does not update. If I put it in a button it throws an exception "syntax error in insert into statement".
Other question: Should I close the connection variable after loading the DataGridView? If so, should I reopen it to perform the update and then reclose it? How does that work?.
Any help would be greatly appreciated.
EDIT: Putted whole class as Tim asked.
public partial class Pantalla_Proyecto : Form
{
private Inicio Inicio;
private List<string> Logueado;
private OleDbConnection conn;
private OleDbDataAdapter Adaptador;
private DataTable Tabla;
private BindingSource Bsource;
private OleDbCommandBuilder Builder;
public Pantalla_Proyecto(Inicio Inicio, List<string> Logueado)
{
this.Inicio =Inicio;
this.Logueado = Logueado;
InitializeComponent();
}
private void Pantalla_Proyecto_Load(object sender, EventArgs e)
{
}
private void importarCDPToolStripMenuItem_Click(object sender, EventArgs e)
{
Importar_CDP Importar_CDP = new Importar_CDP();
Importar_CDP.Show();
}
private void importarListasToolStripMenuItem_Click(object sender, EventArgs e)
{
WindowsFormsApplication1.Formularios.Lista_Lazos.Importar_Listas1 Importar_Listas = new WindowsFormsApplication1.Formularios.Lista_Lazos.Importar_Listas1();
Importar_Listas.Show();
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
}
private void flowLayoutPanel2_Paint(object sender, PaintEventArgs e)
{
}
private void menuStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string sql = "Select * From ["+TABLE (THIS IS A STRING I GET FROM PREVIOUS FORM)+"]";
conn = new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=proyectos\" + Location(this is a string i get on the previous form) + ".mdb;User Id=admin;Password=;");
conn.Open();
// Extraemos info de mi database y la meto en un datatable
Adaptador = new OleDbDataAdapter(sql, conn);
Builder = new OleDbCommandBuilder(Adaptador);
Tabla = new DataTable();
Adaptador.Fill(Tabla);
// LLENO EL DATA GRID VIEW
Bsource = new BindingSource();
Bsource.DataSource = Tabla;
dataGridView1.DataSource = Bsource;
dataGridView1.Dock = DockStyle.Fill;
Adaptador.Update(Tabla);//if i put it here nothing happens
conn.Close();
}
private void dataGridView1_Validating(object sender, CancelEventArgs e)
{
}
private void button1_Click_1(object sender, EventArgs e)
{
conn.Open();
Adaptador.Update(Tabla);//IF i put it here i get an exception
conn.Close();
}
To elaborate, as per OP's request, on the using statement, let's take the comboBox1_SelectedIndexChanged method:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string sql = "Select * From ["+TABLE (THIS IS A STRING I GET FROM PREVIOUS FORM)+"]";
using (conn = new OleDbConnection(#"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=proyectos\" + Location(this is a string i get on the previous form) + ".mdb;User Id=admin;Password=;"))
{
conn.Open();
// Extraemos info de mi database y la meto en un datatable
Adaptador = new OleDbDataAdapter(sql, conn);
// Remove the OleDbCommandBuilder
Tabla = new DataTable();
Adaptador.Fill(Tabla);
// LLENO EL DATA GRID VIEW
Bsource = new BindingSource();
Bsource.DataSource = Tabla;
dataGridView1.DataSource = Bsource;
dataGridView1.Dock = DockStyle.Fill;
// ** NOTE:
// At this point, there's nothing to update - all that
// has happened is that you've bound the DataTable
// to the DataGridView.
Adaptador.Update(Tabla);//if i put it here nothing happens
} // Your connection will be closed at this point when the using
// statement goes out of scope.
}
UPDATE
MSDN says "When you create a new instance OleDbCommandBuilder, any existing OleDbCommandBuilder associated with this OleDbDataAdapter is released."
However, if you want to get away from the OleDbCommandBuilder completely, you can do so (I updated my code above to do just that). Since you believe you're having issues with special characters, it's probably worthwhile to do it this way.
Something like this should help - you'll have to modify the update command based on what your table columns are:
private void button1_Click_1(object sender, EventArgs e)
{
conn.Open();
Adaptador.UpdateCommand = "<Your SQL here>" // I.e., UPDATE [TABLE] SET....
try
{
Adaptador.Update((DataTable)Bsource.DataSource);
}
catch (Exception ex)
{
// Do something with the exception
}
}
This code is a slightly modified version of what MSDN has:
How to: Bind Data to the Windows Forms DataGridView Control
Note that they use a SqlDbCommandBuilder in the example, but the overall principle remains the same.
Based on David-W-Fenton's comment, you might want to do your connection and dataadapter initializations in the Form_Load event, and then close the connection on Form_Closing event.
First thing to check is the runtime path of the Access file that you're actually updating.
If you're using VS.NET, that the MDB file is part of your project, and that the "Copy Local" option is set to true on the MDB file, then it could just be that every time you run your program you overwrite the updates from the last execution.
I'm just mentioning because I've been bitten by this one ;-)
Cheers

Categories