how to subtract two datatables? - c#

I want to subtract two datatables. What i want is that in below Image.
I have the following code and i stacked at last point. Here is what i want to do in the code.
When i click Button1, it will get current data into firstDsData. A few seconds later when i click Button2, it will upload the current data to the secondDsData and merge it together. Then they will merge together into FinalDsData. Differences datatable will get the changes from finaldsdata.
The problem is in the last section. FinalDsData.GetChanges() doesn't work. It says nullreferenceexception. I also tried get changes with RowState.Unchanged/Modified(). They also didn't work.
DataTable firstDsData = new DataTable();
DataTable secondDsData = new DataTable();
DataTable finalDsData = new DataTable();
DataTable DifferenceDataTable = new DataTable();
private void Form1_Load(object sender, EventArgs e)
{
this.dataTable1TableAdapter.Fill(this.dataWE.DataTable1);
}
private void button1_Click(object sender, EventArgs e)
{
firstDsData = dataTable1TableAdapter.GetData();
}
private void button2_Click(object sender, EventArgs e)
{
secondDsData = dataTable1TableAdapter.GetData();
finalDsData.Merge(firstDsData);
finalDsData.AcceptChanges();
finalDsData.Merge(secondDsData); //Until here i can get data into finalDsData. No Problem.
DifferenceDataTable = finalDsData.GetChanges(); // Problem in here.Nullreferenceexception
ultraGrid2.SetDataBinding(DifferenceDataTable, DifferenceDataTable.TableName);
}

If your only goal is to show changes on a grid then you can use LINQ to find difference between two tables like:
var changes = (from dr1 in firstDsData.AsEnumerable()
from dr2 in secondDsData.AsEnumerable()
where dr1.Field<string>("Name") == dr2.Field<string>("Name")
select new
{
Name = dr1.Field<string>("Name"),
Value = dr1.Field<decimal>("Value") - dr2.Field<decimal>("Value")
}).ToList();
To show it to your grid you can do:
ultraGrid2.DataSource = changes;
If you want a DataTable for the output then you can convert your LINQ results to a DataTable, see Convert select new to DataTable?

Related

How to bind Access database to DataTable?

I'm new to C# and Visual Studio.
I'm working on a project that is searching through a database of information.
I want to bind a database (Microsoft access file) to my datagridview
but I want it to work with my preexisting code which utilizes a datatable converted into a dataview.
My database has a lot of information and I don't want to put it in manually. I've tried binding the information directly to the datagridview (through datasource in the properties) but then searching doesn't work**. I've looked into sql but im trying to avoid learning 2 languages at the same time.
My projects basic functionality contains: 1 combobox (idCbo) containing the search query's 1 datagridview for displaying the information
this setup is for searching one column only, im going to duplicate the code for the oher columns
The name of the column in the datagridview selects the column(id) for filtering then the combo box(idCbo) searches that column for matching characters in the datagridview and comboBox list.
the combo box contains the values 1-100 for searching the column
public partial class Form1 : Form
{
DataTable dt = new DataTable();
DataView dataView;
public Form1()
{
InitializeComponent();
dt.Columns.Add("id", typeof(int));
for (int i = 0; i < 100; i++)
dt.Rows.Add(i);
dataView = new DataView(dt);
this.dataGridView1.DataSource = dataView;
}
private void idCbo_SelectedIndexChanged(object sender, EventArgs e)
{
string query = idCbo.Text;
dataView.RowFilter = $"convert(id,'System.String') LIKE '%{query}%'";
}
}
**
Binding the database to the datagridview while using this code renders column titles but not the information and the code cannot access the database, columns or the rows System.Data.EvaluateException: 'Cannot find column ...
Big thanks to Johng for assisting me with the code :)
CURRENT WORKING CODE
public Form1()
{
InitializeComponent();
}
public static BindingSource gridBindingSource;
private void idCbo_SelectedIndexChanged(object sender, EventArgs e)
{
string query = idCbo.Text;
gridBindingSource = (BindingSource)dataGridView1.DataSource;
if (gridBindingSource != null)
{
if (query == "All")
{
gridBindingSource.Filter = "";
}
else
{
gridBindingSource.Filter = "convert(id,'System.String') LIKE '%" + query + "%'";
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the '_InfoFinalv_2___CopyDataSet.Info' table. You can move, or remove it, as needed.
infoTableAdapter.Fill(this._InfoFinalv_2___CopyDataSet.Info);
idCbo.Items.Add("All");
for (int i = 1; i < 100; i++)
{
idCbo.Items.Add(i);
}
idCbo.SelectedIndex = -1;
}
private void idReset_Click(object sender, EventArgs e)
{
idCbo.SelectedIndex = -1;
}
If you have set up the grids data source in the designer “correctly” then using the DataView as you want can be simplified by using the existing BindingSource that is usually created when you set up the grid’s data source in the designer.
We can use the existing grid’s BindingSource and then use it’s Filter property as opposed to converting the BindingSource to a DataView to filter. This will allow us to set the filter in the grid WITHOUT having to “change” the grids data source.
Remove all the code you have in the form constructor obviously leaving the InitializeComponent(); and add the code below to the forms Load event. In the load event all we do is set up the combo box with the proper values. I added an “All” option to allow the user to “un-filter” the data in the grid.
private void Form1_Load(object sender, EventArgs e) {
// TODO: This line of code loads data into the 'database1DataSet.EmployeeDT' table. You can move, or remove it, as needed.
employeeDTTableAdapter.Fill(this.database1DataSet.EmployeeDT); // <- created by the designer
idCbo.Items.Add("All");
for (int i = 1; i < 100; i++) {
idCbo.Items.Add(i);
}
idCbo.SelectedIndex = 0;
}
Then in the combo boxes SelectedIndexChanged event... change the code as shown below. Cast the grids DataSource to a BindingSource and then use its Filter property.
private void idCbo_SelectedIndexChanged(object sender, EventArgs e) {
string query = idCbo.Text;
BindingSource GridBS = (BindingSource)dataGridView1.DataSource;
if (GridBS != null) {
if (query == "All") {
GridBS.Filter = "";
}
else {
GridBS.Filter = "EmpID LIKE '%" + query + "%'";
}
}
}
Here's the tip:
On the form load, make an ajax call to the database and fetch only the required data columns. Return data will be in JSON that can be used as data for DataTable.
I used it in an MVC project recently and it works fine. If you would like I can share the detailed code and logic.
Not sharing the code since I'm not sure if you are on .Net MVC.

How to show the dataGrid from a text search filter with c# in postgresql

I have a text button that should filter the name of a person from a data table. the code is:
private void txtSearch_TextChanged(object sender, EventArgs e)
{
DataView DT = new DataView(dataTable);
DT.RowFilter = string.Format("nome_docente LIKE '%{0}%'", txtSearch.Text);
dgvTabela.DataSource = DT;
}
When running the code after the table loads, when I search for a name all the table disappears, and nothing is shown.
Can someone give me a tip on this?
Best regards

What is the most efficient way to sync two datagridviews?

Here is what I am trying to accomplish:
I have two datagriddviews. Datagridview1 holds a list of urls. Datagridview2 is basically a bookmarking system. A user can right-click on a url in datagridview1 and select to favorite or "bookmark" it. That row will then be copied to datagridview2. The font on the row on datagridview1 will then become bolded to show that it has been favorited and added to datagridview2. How do I keep these two synced? For example if a user removes a favorite on datagridview2 it should become unbolded on datagridview1 as it is no longer a favorite. What is an efficient way to keep these 2 synced to each other since the indexes will be different? I Had through about just iterating through each row to see if the cell content strings were equal and then unbolding it based off that but that seems very inefficient. Any suggestions on how to accomplish this?
As a good option you can have a data source like a DataTable having and string Url and a bool Favorite column.
Then, bind the first grid to the data table as its DataSource.
Bind the second grid to a DataView that you created from your data table and set Favorite=true as its Filter.
Then handle RowPrePaint event of first DataGridView and set the font to be bold if the row has favorite=true, else set the font to be regular.
For add button and remove button, set the value of favorite column on data row behind the current row and then call EndEdit on data row.
Initialization
private void Form1_Load(object sender, EventArgs e)
{
//Create DataTable
var data = new DataTable();
data.Columns.Add("Url", typeof(string));
data.Columns.Add("Favorite", typeof(bool));
//Fill Data
data.Rows.Add("http://stackoverflow.com", true);
data.Rows.Add("http://bing.com", false);
data.Rows.Add("http://google.com", false);
//Set DataBidnings to allUrlsDGV
this.allUrlsDGV.DataSource = data;
//Set DataBidnings to favoriteUrlsDGV
var favoriteData = new DataView(data);
favoriteData.RowFilter = "Favorite=true";
this.favoriteUrlsDGV.DataSource = favoriteData;
}
RowPrePaint
private void allUrlsDGV_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
var f = e.InheritedRowStyle.Font;
var drv = (DataRowView)allUrlsDGV.Rows[e.RowIndex].DataBoundItem;
if (drv.Row.Field<bool>("Favorite") == true)
allUrlsDGV.Rows[e.RowIndex].DefaultCellStyle.Font = new Font(f, FontStyle.Bold);
else
allUrlsDGV.Rows[e.RowIndex].DefaultCellStyle.Font = new Font(f, FontStyle.Regular);
}
Add and Remove Buttons
private void AddButton_Click(object sender, EventArgs e)
{
if (allUrlsDGV.CurrentRow == null)
return;
var drv = (DataRowView)allUrlsDGV.CurrentRow.DataBoundItem;
drv.Row["Favorite"] = true;
drv.Row.EndEdit();
}
private void RemoveButton_Click(object sender, EventArgs e)
{
if (favoriteUrlsDGV.CurrentRow == null)
return;
var drv = (DataRowView)favoriteUrlsDGV.CurrentRow.DataBoundItem;
drv.Row["Favorite"] = false;
drv.Row.EndEdit();
}

A relation named ... already belongs to this DataSet

I can't fix this error that I get A Relation named 'PlaneAirline' already belongs to this DataSet. I have tried to change the name of the relation but I get the same error
Here is my code:
private void getData()
{
SqlDataAdapter parentDataAdapter = new SqlDataAdapter("select * from Airline", connection);
parentDataAdapter.Fill(ds, "Airline");
SqlDataAdapter childDataAdapter = new SqlDataAdapter("select * from Plane", connection);
childDataAdapter.Fill(ds, "Plane");
DataColumn parentColumn = ds.Tables["Airline"].Columns["airline_id"];
DataColumn childColumn = ds.Tables["Plane"].Columns["airline_id"];
rel = new DataRelation("PlaneAirline", parentColumn, childColumn);
ds.Relations.Add(rel);
parentBindingSource.DataSource = ds;
parentBindingSource.DataMember = "Airline";
childBindingSource.DataSource = parentBindingSource;
childBindingSource.DataMember = "PlaneAirline";
}
private void dg_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
private void AirlineReservation_Load(object sender, EventArgs e)
{
parentDataGridView.DataSource = parentBindingSource;
childDataGridView.DataSource = childBindingSource;
getData();
}
Could you please help me
I think your problem is that you are calling GetData() method on CellContentClick event. This event will get fired when the content within a cell is clicked. Hence whenever you are clicking the cell your code is trying to add a relation which is already present when you first clicked a cell.
Probably you need to move the GetData() call to Form Load as given in the tutorial you have given.
Hope this helps.
On every click in your DataGrid (I'm assuming that dg_CellContentClick is tha click handler for the data grid cell) you're calling getData, where you try to add the relation PlaneAirlineover and over again.
Try to move the lines
rel = new DataRelation("PlaneAirline", parentColumn, childColumn);
ds.Relations.Add(rel);
to where you initially create or define your variable ds (I think it's a DataSet).

How to update DataGrid on click event?

I have the following code which updates the data base on a button click by calling a function additems.
static DataTable additems(string itema, string itemb, string itemc, string itemd)
{
DataTable listitems = new DataTable();
listitems.Columns.Add("itema");
listitems.Columns.Add("itemb");
listitems.Columns.Add("itemc");
listitems.Columns.Add("itemd");
// Add new items
listitems.Rows.Add(itema, itemb, itemc, itemd);
return listitems;
}
private void button1_Click(object sender, EventArgs e)
{
// add to data grid
dataGridView1.DataSource = additems("New text", "Almonds", "Butter", "Salt");
}
I wanted the above code to create new data grid. And it works fine for single data..
but for multiple data how can i achieve such heights?
I have a new variable (not using any database). Whenever button1 is clicked this variable needs to be loaded to data table so that it can instantly add to datagridview1.
I need some concepts...
well, you could change the method sig to take a new parameter for the datatable ...
if that's null, create a new table like you do now ... if it's not null, simply add a new row to that existing table
//quick and dirty example
static DataTable additems(string itema, string itemb, string itemc, string itemd, DataTable foo)
{
DataTable listitems = foo;
if(foo == null)
{
listitems = new DataTable();
listitems.Columns.Add("itema");
listitems.Columns.Add("itemb");
listitems.Columns.Add("itemc");
listitems.Columns.Add("itemd");
}
// Add new items
listitems.Rows.Add(itema, itemb, itemc, itemd);
return listitems;
}
private void button1_Click(object sender, EventArgs e)
{
// add to data grid
dataGridView1.DataSource = additems("New text", "Almonds", "Butter", "Salt", (DataTable)dataGridView1.DataSource);
}
you also might want to think about storing that datatable in a private field, instead of using (DataTable)dataGridView1.DataSource, but the question wasn't about good coding style ;)

Categories