Compare Two Datatable that has same schema and N no of columns - c#

I have two DataTables both has same no of columns and column names.Am in need of comparing both for the different rows.Which means even if one cell doesnt match the row should be plotted.I tried with
table1.Merge(table2);
DataTable modified = table2.GetChanges();
But this is returning null.
Where as
IEnumerable<DataRow> added = table1.AsEnumerable().Except(table2.AsEnumerable());
This is returning the table1 values alone even there are different values for a some cells in table1 compared to table2.
Can anyone help me for this comparison.Various sites i referred,the instruction said was to compare each column in a row but since i have N no of columns i cant go with that.I need a smarter way of comparison which would be efficient.
Thanks in advance

IEnumerable<DataRow> added = table1.AsEnumerable().Except(table2.AsEnumerable());
should be changed to
IEnumerable<DataRow> added = table1.AsEnumerable().Except(table2.AsEnumerable(),DataRowComparer.Default);
Because DataRows don't know how to compare themselves to eachother on their own. You can also provide your own equality delegate instead of DataRowComparer.Default if required.

Have you tried using merge? http://msdn.microsoft.com/en-us/library/fk68ew7b.aspx
Datatable1.Merge(datatable2);
DataTable DataTable3 = Datatable2.GetChanges();

Related

How to compare 2 datatables without any loops and key relationships in c# or linq

What is the best way to compare two DataTables. If I have 2 Datatables with same data, if I change any value in datatable 2, while comparing I don't want to check row by row, count and memory with datatable 1.
If you get 2 DataTable object and want to check for differences between them then you'd probably must use loop.
If you want to react on change in object then you can use RowChanged event.
If you'd like to get changes since last read then use GetChanges() method.
A .Except() might be useful here. It produces a set difference of two sequences.
Two datatables - mtbl for master data, dtbl for detail data or the new data you're comparing to.
var differences = dtbl.AsEnumerable().Except(mtbl.AsEnumerable(), DataRowComparer.Default);
return differences.Any() ? differences.CopyToDataTable() : new DataTable();
return differences.Any() ? differences.CopyToDataTable() : new DataTable();

More Efficient way to Copy DataRows into another DataTable

This question is about finding a more efficient way for a simple problem. I have two DataTables with same structure (i.e. the Columns have same name with same Ordinals). Let them Call DataTable A and DataTable B. Assume both have 100 rows. Now I want to copy all the rows of DataTable B to DataTable A without removing rows from DataTable A. So in the end DataTable A has 200 rows. I did it as shown below.
for (int i = 0; i < B.Rows.Count - 1;i++ )
{
DataRow dr = B.Rows[i];
A.Rows.Add(dr);
}
The issue is I do not want to loop. Is there a direct way to copy it, without looping. The whole 100 rows at once. Is there a function which specifies the set of rows you want to copy.
As far as I know, there is no other way of copying multiple rows from one Datatable to another than iterating through all the rows. In fact, on MSDN there is an article telling you how to copy rows between Datatables and uses an iteration loop.
https://support.microsoft.com/en-gb/kb/305346
There are some problems with your simple approach because it doesnt handle primary key violations. Try BeginLoadData, LoadDataRow and EndLoadData. This should be more efficient. BeginLoadData and EndLoadData call only once.
If you just need a new independent DataTable instance to work with and do not need to append rows to an existing DataTable, then the DataView.ToTable() method is very convenient.
https://msdn.microsoft.com/en-us/library/a8ycds2f(v=vs.110).aspx
It creates a separate copy with the same schema and content.
DataTable objTableB = objTableA.DefaultView.ToTable();

"Filtering" DataTable by Column NOT Rows

Given a DataTable with Columns A, B, C, D
looking for a clean way to restrict columns to say A, C
similar to how the DataView restricts the Rows in a DataView
Typically a DataTable has a relatively small, fixed number of named columns, and a potentially large, variable number of unnamed rows. Hence filtering makes sense for rows, but not for columns.
Most applications would simply ignore the columns they are not interested in.
I don't think there's any way to do what you want, short of cloning the DataTable and deleting the columns you don't want.
Or perhaps pivoting the DataTable so that columns become rows.
Found the solution, posting it here for others who might land here
DataView.ToTable() method described here http://msdn.microsoft.com/en-us/library/wec2b2e6.aspx
used as
DataTable.DefaultView.ToTable( flag, );

How to create LookUp fields in DataGridView?

In my DataGridView I'am displaying a buch of columns from one table. In this table I have a column which points to item in another table. As you may already guessed, I want to display in the grid in one column some text value from the second table instead of and ItemID.
I could not find a right example on the net how to do this.
Lets assume that I have two tables in databes:
Table Users:
UserID UserName UserWorkplaceID
1 Martin 1
2 John 1
3 Susannah 2
4 Jack 3
Table Workplaces:
WorkplaceID WorkplaceName
1 "Factory"
2 "Grocery"
3 "Airport"
I have one untyped dataset dsUsers, one binding source bsUsers, and two DataAdapters for filling dataset (daUsers, daWorkplaces).
Code which I am performing:
daUsers.Fill(dsUsers);
daWorkplaces.Fill(dsUsers);
bsUsers.DataSource = dsUsers.Tables[0];
dgvUsers.DataSource = bsUsers;
At this point I see in my dgvUsers three columns, UserID, UserName and UserWorkplaceID. However, instead of UserWorkplaceID and values 1,2,3 I would like to see "Factory", "Grocery" and so on...
So I've added another column to dgvUsers called "WorkplaceName" and in my code I am trying to bind it to the newly created relation:
dsUsers.Relations.Add("UsersWorkplaces", dsUsers.Tables[1].Columns["WorkplaceID"], dsUsers.Tables[0].Columns["UserWorkplaceID"]);
WorkplaceName.DataPropertyName = "UsersWorkplaces.WorkplaceName";
Unfortunately that doesn't work. Relation is created without errors but fields in this column are empty after running the program.
What I am doing wrong?
I would like to also ask about an example with LookUp combobox in DataGridView which allow me to change the UserWorkplaceID but instead of numeric value it will show a tex value which is under WorkplaceName.
Thanks for your time.
In my opinion, the best decision would be to use the DataGridViewComboBoxColumn column type. If you do it, you should create a data adapter with lookup data beforehand and then set DataSource, DataPropertyName, DisplayMember, and ValueMember properties of the DataGridViewComboBoxColumn. You could also set the DisplayStyle property to Nothing to make the column look like a common data column. That's it.
I don't know if you can do exactly what you want, which seems to be binding the DataGridView to two different DataTable instances simulataneously. I don't think the DataGridView class supports that -- or if it does it's a ninja-style move I haven't seen.
Per MSDN, your best bet is probably using the CellFormatting event on the DataGridView and check for when the cell being formatted is in the lookup column, then you could substitute your value from the other table. Use an unbound column for the WorkplaceName column, hide the UserWorkplaceID column and then implement the CellFormatting event handle to look up the value in the row, e.g.:
private void dgv_CellFormatting(object sender,
DataGridViewCellFormattingEventArgs e)
{
if (dgv.Columns[e.ColumnIndex].Name.Equals("WorkplaceName")
{
// Use helper method to get the string from lookup table
e.Value = GetWorkplaceNameLookupValue(
dataGridViewScanDetails.Rows[e.RowIndex].Cells["UserWorkplaceID"].Value);
}
}
If you've got a lot of rows visible, this might impact performance but is probably a decent way to get it working.
If this doesn't appeal to you, maybe use the DataTable.Merge() method to merge your lookup table into your main table. A quick glance at one of my ADO.NET books suggests this should work, although I have not tried it. But I'm not sure if this is too close to the idea suggested previously which you shot down.
As for your second question about the lookup combobox, you should really post it in a separate question so it gets proper attention.
You could make SQL do the job instead. Use a join to return a table with Workplace names instead of IDs, output that table into a dataset and use it instead.
eg.
SELECT A.UserID, A.UserName, B.WorkplaceID
FROM Users A
JOIN Workplaces B ON A.UserWorkplaceID = B.WorkplaceID
Then use its output to fill dsUsers.

Is it possible to remove a duplicate value from a datatable in c#?

I have a datatable with a column MobileNo.... My datatable has 150 rows and each row has MobileNo... Now how to check every MobileNo is unique by parsing all the datarows of the datatable in c#?
EDIT:
"This datatable is being created by reading a CSV file"
Use Linq and Group By the MobileNo then you will need to traverse the collection and see which MobileNo's have multiple records and then do whatever you wish to remove what you deem is duplicated.
Edit: From Linq 101 Samples.
Try
DataTable.DefaultView.ToTable(bool distinct, string[] ColumnNames)
the third overload on that is what your looking for I believe, let me know how you get on.
Specify which columns are to be deduped in the string[]
And a true false for distinct records
So you can either just select a subset of data out or dedupe by setting distinct to true.
You will need to do some jiggery pokery to get your dataset how you want it, but I think thats what your after.

Categories