Update database linked to DataGrid dynamically - c#

I want to put several buttons on my WPF form and update dynamically my DataGrid with the data from a different database for each button, let say, I have 3 databases and 3 buttons, and when you push one button you get the data from 1 different database.
But I want the data on the DataGrid to update back into the database when a change is made on the Grid, so I don't have to program all the "save" stuff.
Right now, the code that I have is this:
try
{
OleDbConnection conn = new OleDbConnection(
"Provider=Microsoft.Jet.OLEDB.4.0; " +
"Data Source=MaterialDB.mdb");
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM myTable", conn);
myDataSet = new DataSet();
adapter.Fill(myDataSet, "myTable");
var be = CatalogsGrid.GetBindingExpression(DataGrid.ItemsSourceProperty);
CatalogsGrid.DataContext = myDataSet;
CatalogsGrid.ItemsSource = myDataSet.Tables[0].DefaultView;
Binding nbe = new Binding();
nbe.Source = myDataSet;
nbe.Mode = BindingMode.TwoWay;
nbe.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
nbe.Path = new PropertyPath("myTable");
nbe.BindsDirectlyToSource = true;
CatalogsGrid.SetBinding(DataGrid.ItemsSourceProperty, nbe);
CatalogsGrid.Items.Refresh();
}
This code loads the data from a database into the grid, but I edit the data and it doesn't update back into the MS Access table.
Oh, it is still not coded but the "myTable" should be a string where I put the name of the different tables I want to show and update from the grid.
What am I missing?

The DataGrid does not save changes automatically, that's up to you (your application) to decide, but it writes back changes to the underlying DataTable.
So as I understand, you want to avoid having a save button and save changes back to the database immediately after they have changed. What you need now is to know when something has changed, and your DataSet can help you with that:
myDataSet = new DataSet();
myDataTable = myDataSet.Tables["myTable"];
adapter.Fill(myDataTable);
// Update the DB whenever a row changes
myDataTable.OnRowChanged += (s, e) =>
{
adapter.Update(myDataTable);
}

Create a centralized method that will update the data that is used to bind the data. Create a save button and call the below function. It will save the network traffic for being save the data on every change.
public void UpdateDb ( OleDbDataAdapter adap, DataSet ds)
{
var build= new OleDblCommandBuilder (adap);
adap.Update (ds);
}
Just you need to pass the parameter and it will update the changes made to dataset.

Taking #Bernhard answer as a starting point, had to add the update command and some tweaking, it is now working.
This is the final code:
try
{
OleDbConnection conn = new OleDbConnection(
"Provider=Microsoft.Jet.OLEDB.4.0; " +
"Data Source=MaterialDB.mdb");
//conn.Open();
OleDbDataAdapter adapter = new OleDbDataAdapter("SELECT * FROM myTable", conn);
myDataSet = new DataSet();
adapter.Fill(myDataSet, "myTable");
DataTable myDataTable = myDataSet.Tables["myTable"];
// Create the UpdateCommand.
OleDbCommand command = new OleDbCommand(
"UPDATE myTable SET Type = #Type, Description = #Description " +
"WHERE ID = #ID", conn);
// Add the parameters for the UpdateCommand.
command.Parameters.Add("#Type", OleDbType.Char, 255, "Type");
command.Parameters.Add("#Description", OleDbType.Char, 255, "Description");
command.Parameters.Add("#ID", OleDbType.Integer, 5, "ID");
adapter.UpdateCommand = command;
// Update the DB whenever a row changes
myDataTable.RowChanged += (s, f) =>
{
adapter.Update(myDataTable);
};
var be = CatalogsGrid.GetBindingExpression(DataGrid.ItemsSourceProperty);
CatalogsGrid.DataContext = myDataSet;
CatalogsGrid.ItemsSource = myDataSet.Tables[0].DefaultView;
Binding nbe = new Binding();
nbe.Source = myDataSet;
nbe.Mode = BindingMode.TwoWay;
nbe.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
nbe.Path = new PropertyPath("myTable");
nbe.BindsDirectlyToSource = true;
CatalogsGrid.SetBinding(DataGrid.ItemsSourceProperty, nbe);
CatalogsGrid.Items.Refresh();
}
Thanks for the help.

Related

Selecting other Tables of database to show on a DataGridView

I want to display many tables of data in my datagridview.
I use combobox to select other tables but it can't read and can't show table, so I set my combobox to its 1st table but every time I refresh the table it always getting back to the table I set
private void UpdateDataGrid()
{
using (IDbConnection dbconnection = new SQLiteConnection(conn))
{
dbconnection.Open();
//the other tables are Electrical and Tools
cbTable.Text = "Plumbing";
SQLiteDataAdapter dataAdapter = new SQLiteDataAdapter("SELECT * FROM " + cbTable.Text + "", conn);
ds = new System.Data.DataSet();
dataAdapter.Fill(ds, "Item_InFo");
dgvItems.DataSource = ds.Tables[0];
}
}

Editing a datatable and sending it back to a database

With my program I have a datatable that gets populated with records fetched from a database. This is displayed in a datagrid view and when a cell is clicked it loads all the values into textboxes. When a save button is clicked it will then save the textbox values back into the datatable. However how can I send this datatable back to the database and have it update the records?
Here is my code to load the records:
indexRow = e.RowIndex;
DataGridViewRow row = dgv_ReturnSearch.Rows[indexRow];
tb_editFirstName.Text = row.Cells[1].Value.ToString();
tb_editLastName.Text = row.Cells[2].Value.ToString();
tb_editAge.Text = row.Cells[3].Value.ToString();
tb_editPostCode.Text = row.Cells[4].Value.ToString();
tb_editMobNum.Text = row.Cells[5].Value.ToString();
tb_editEmail.Text = row.Cells[6].Value.ToString();
tb_editAllergies.Text = row.Cells[7].Value.ToString();
tb_editDOB.Text = row.Cells[8].Value.ToString();
tb_editGender.Text = row.Cells[9].Value.ToString();
Here is my code to save them
DataGridViewRow newDataRow = dgv_ReturnSearch.Rows[indexRow];
newDataRow.Cells[1].Value = tb_editFirstName.Text;
newDataRow.Cells[2].Value = tb_editLastName.Text;
newDataRow.Cells[3].Value = tb_editAge.Text;
newDataRow.Cells[4].Value = tb_editPostCode.Text;
Logic.SQLQueriesUtility.Adapter.Update(dt);
However this doesn't actually update the database, only the local datatable. When it is loaded again all the changes revert.
Thanks
To load a gridview with data from the database you'll need to use DataTable and DataAdapter then bind the grid. it should look something like this:
private void CustomersBindGrid()
{
using (SqlConnection con = new SqlConnection(mycon))
{
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "SELECT * FROM Customers";
cmd.Connection = con;
DataTable dt = new DataTable();
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
sda.Fill(dt);
Gridview1.DataSource = dt;
Gridview1.DataBind();
}
}
con.Close();
}
}
Try updating the database directly:
private void SaveEdits_Click()
{
using (SqlConnection con = new SqlConnection(mycon))
{
con.Open();
using (SqlCommand cmd = new SqlCommand())
{
cmd.CommandText = "UPDATE Customers set firstname= #FN , lastname= #LN , age = #AG , postcode= #PC where CustomerID = #CustID";
cmd.Connection = con;
cmd.Parameters.AddWithValue("#CustID", cid);
cmd.Parameters.AddWithValue("#FN", tb_editFirstName.Text);
cmd.Parameters.AddWithValue("#LN", tb_editLastName.Text);
cmd.Parameters.AddWithValue("#AG", tb_editAge.Text);
cmd.Parameters.AddWithValue("#PC", tb_editPostCode.Text);
cmd.ExecuteNonQuery();
}
}
CustomersBindGrid();
MessageBox.show("Information Updated!");
}
}
You need to edit this update command to your columns in the database and get a way to read the customer id so the condition actually work and update the database.
In your posting, you don't write, how your client is developed...
Normally, this would be done with a SQL update command.
Therefore (in the Microsoft universe) the SqlClient (System.Data.SqlClient Namespace) can be used.
As soon as the user press the save button, you overtake the relevant textbox.text values in variables, change datatypes if necessary, generate an SQL update string to update the data on your SQL server.
Example SQL update string:
Update TableName set ColumnName1Text = 'some text', ColumName2Integer = 12, ColumnName.... = ... where ColumnNameKey = KeyToDatatable
Then you submit the SQL command (SQL update string) to the SQL server via SqlClient (SqlCommand).
But therefore you need a unique key for the where clause (in the example KeyToDatatable) so that only the row with the key is updated.
The key normally is queried from the DataTable (with the other fields) to show the data (in your grid) and then taken over to the update command (can be "hided" from the user, that don't has to know the key).
Well I managed to fix it by doing:
DataGridViewRow newDataRow = dgv_ReturnSearch.Rows[indexRow];
dt.Rows[indexRow]["first_name"] = tb_editFirstName.Text;
dt.Rows[indexRow]["last_name"] = tb_editLastName.Text;
dt.Rows[indexRow]["age"] = tb_editAge.Text;
dt.Rows[indexRow]["postcode"] = tb_editPostCode.Text;
dt.Rows[indexRow]["mobile_num"] = tb_editMobNum.Text;
dt.Rows[indexRow]["email"] = tb_editEmail.Text;
dt.Rows[indexRow]["allergies"] = tb_editAllergies.Text;
dt.Rows[indexRow]["DOB"] = tb_editDOB.Text;
dt.Rows[indexRow]["gender"] = tb_editGender.Text;
Logic.SQLQueriesUtility.Adapter.Update(dt);
Instead of what I was doing before, now it works perfectly and any changes are saved back to the database.

Load data to a data set from data table in C#

I have a dataset called "dts_Material_Report" which is used to generate reports.In that data set I have a tableAdapter called "dt_report_Received_Materials".
Previously I have load the data to that table adapter with following code ,
private void generate_report( string qry )
{
string query, qry1;
query = qry;
int pr_id = Form_Common_PCM.pr_id;
clz_Common_SqlConnection con = new clz_Common_SqlConnection();
SqlDataAdapter sda = new SqlDataAdapter(query, con.ActiveCon());
DataSet dts = new DataSet();
sda.Fill(dts, "dt_report_Received_Materials");
rdc.SetDataSource(dts);
crystalReportViewer1.ReportSource = rdc;
crystalReportViewer1.DisplayToolbar = true;
crystalReportViewer1.Show();
}
But currently I am having all the data which I need to generate the report in one of my data table called "dt_mat_cost".
int Ref_ID_s_category;
Ref_ID_s_category = Convert.ToInt16(cbo_sub_category .SelectedValue );
int pro_id = Form_Common_PCM.pr_id;
clz_Received_Material_Summary rms = new clz_Received_Material_Summary();
DataTable dt_mat_cost = rms.Summary_Material_Cost_Filter_By_Project_By_Sub_Category(Ref_ID_s_category);
Now i want to load those data from "dt_mat_cost" to my tableAdapter "dt_report_Received_Materials" .Is there any way to do this.
Thanks in Advance.
One way to resolve this would be to put the DataTable into a DataSet and then run the crystal code as shown below. You may be able to just set the ReportSource to the datatable but I do not recall off the top of my head if that will work.
DataTable dt_matCost = rms.Summary_Material_Cost_Filter_By_Project_By_Sub_Category(Ref_ID_s_category);
DataSet dts = new DataSet();
dts.Tables.Add(dt_matCost);
//ds.Tables[0].TableName = "Whatever CR thinks it is"; // may need to set for CR
rdc.SetDataSource(dts);
crystalReportViewer1.ReportSource = rdc;
crystalReportViewer1.DisplayToolbar = true;
crystalReportViewer1.Show();

how to select specific field using a filter from access in C#

in C# and windows Form,
I have a database like this:
and this is how I using a class put it's data into a datagridview:
class DBConnection
{
public static void GetList(Form2 frm2)
{
string DBPath = Application.StartupPath;
OleDbConnection Connection = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source="+DBPath+#"\DataBase\SampleFeeds.accdb");
OleDbDataAdapter DataA = new OleDbDataAdapter("Select * from FeedLibrary", Connection);
DataTable Dtable = new DataTable();
DataA.Fill(Dtable);
frm2.SelectedFeeddataGridView.DataSource = Dtable;
}
}
and this is my form load:
private void Form2_Load(object sender, EventArgs e)
{
DBConnection.GetList(this);
}
So far everything is ok.
now I have a question:
for example I have a list box FeedSelectListBox,
I want to when user click on a button GrassLegumeForagebtn my FeedSelectListBox fill with only all of Feed Names that are in the category of Grass / Legume Forage.
how should I do that ?
with help of Damirchi My problem solved
//-----------------
But now I have another question:
I want to when user select a feed from list box all of it's data from data base (like name, number, feed type and ,,,) put in a data grid view.
I used this code on my SelectFeedbtn but it doesn't work :
private void SelectFeedbtn_Click(object sender, EventArgs e)
{
string StrCon = System.Configuration.ConfigurationManager.ConnectionStrings["FeedLibraryConnectionString"].ConnectionString;
OleDbConnection Connection = new OleDbConnection(StrCon);
string FeedSelectedID = FeedSelectListBox.SelectedValue.ToString();
OleDbDataAdapter DataA = new OleDbDataAdapter("Select * from FeedLibrary where ID = 'FeedSelectedID'" , Connection);
DataTable DTable = new DataTable();
DataA.Fill(DTable);
SelectedFeeddataGridView.DataSource = DTable;
}
And ValueMember property of FeedSelectListBox is ID but the error is :
An unhandled exception of type 'System.Data.OleDb.OleDbException' occurred in System.Data.dll.
I even use this query but it still doesn't work:
OleDbDataAdapter DataA = new OleDbDataAdapter("Select * from FeedLibrary where ID =" FeedSelectListBox.SelectedValue , Connection);
at first you most set the DisplayMember and ValueMember properties of FeedSelectListBox and use this code on click event.
you can put this code on GrassLegumeForagebtn click event.
string DBPath = Application.StartupPath;
OleDbConnection Connection = new OleDbConnection(#"Provider=Microsoft.ACE.OLEDB.12.0;Data Source="+DBPath+#"\DataBase\SampleFeeds.accdb");
OleDbDataAdapter DataA = new OleDbDataAdapter("Select * from FeedLibrary where category='Grass / Legume'", Connection);
DataTable Dtable = new DataTable();
DataA.Fill(Dtable);
frm2.FeedSelectListBox .DataSource = Dtable;

Error loading image in the DataGridView in C#

I am trying to load data from the database and display it in the DataGridView, I can display the text just fine but when I try to load an image I get an error. My code is
private void LoadData()
{
using (MySqlConnection conn = new MySqlConnection(connectionManager.connectionString))
{
try
{
//MySqlDataAdapter _adapter = new MySqlDataAdapter("SELECT `ID`, `First Name`, `Last Name`, `Email`, `Mobile`, `Course`, `Gender` FROM student_img", conn);
MySqlDataAdapter _adapter = new MySqlDataAdapter("SELECT `ID`, `First Name`, `Last Name`, `Email`, `Mobile`, `Course`, `Gender` , `Image` FROM student_img", conn);
DataSet _dataset = new DataSet();
_adapter.Fill(_dataset, "table");
dataGridViewStudent.DataSource = _dataset;
dataGridViewStudent.DataMember = "table";
lblRecords.Text = dataGridViewStudent.Rows.Count.ToString();
DataGridViewImageColumn Image = new DataGridViewImageColumn();
Image = (DataGridViewImageColumn)dataGridViewStudent.Columns[7];
}
catch (Exception ex)
{
MessageBox.Show("Connection Error!\n" + ex.Message, "Error Message",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
The error messages I get is
These two lines make no sense:
DataGridViewImageColumn Image = new DataGridViewImageColumn();
Image = (DataGridViewImageColumn)dataGridViewStudent.Columns[7];
If your columns are being auto-generated the image column will be generated as such and work without further code. This is the simplest way.
And since you don't create any other columns that seems to be what you are doing. So what shall those lines achieve??
Especially as you don't add the extra column anywhere? (Which btw you can't do anyway, as it is already part of the columns collection..)
If you create your dgv columns in code you will have to give each the correct type and connect each one to the right datasource column and add them to the DGV:
string sql = "Select preview, text from Covers;";
..
..
DataSet ds = new DataSet();
adapter.Fill(ds);
// either simply set this to true or..
dataGridView1.AutoGenerateColumns = false;
// add all columns..
DataGridViewImageColumn dvgic = new DataGridViewImageColumn();
// setting their names
dvgic.Name = "preview";
dvgic.HeaderText = "Preview";
// and relating them to the data source fields..
dvgic.DataPropertyName = "preview";
dataGridView1.Columns.Add(dvgic);
dataGridView1.Columns.Add("text", "Text");
dataGridView1.Columns["text"].DataPropertyName = "text";
dataGridView1.DataSource = ds.Tables[0];
If for some reason you need to set an ImageColumn cell to an Image, be it from whatever source, including a db field that is feeding into a memorystream, then you will have to set the Value of the cell, not the cell itself.
But your error message seems to indicate that at least some of your data are not valid images..

Categories

Resources