I have a DataTable with data loaded from an external source, one of the column is an int.
I'd like to add a column to the DataTable, containing a description of that int.
I have a Dictionary, or in some cases something like:
Pair<int,string> mapping_values[] = {
new Pair<String, int>("start", 3),
new Pair<String, int>("end", 6),
... etc.
};
The DataTable contains a "status_value", an integer which maps to the int in mapping_values
DataTable tbl = ...;
tbl.Columns.add("Status Text",typeof(string));
Now, I'd like to fill the values of this new Status Text column with
the string from mapping_values where tbl["status_value"] matches the integer (3 or 6 in this case) and fill in "start" or "end". Can linq help me here, or something else ?
You'll need to manually populate the column in a loop.
To do that, you should put your mapping in a dictionary.
For example:
var mapping = mapping_values.ToDictionary(p => p.Value1, p => p.Value2);
foreach(DataRow row in table.Rows)
row["Status Text"] = mapping[row.Field<int>("Status Value")];
Related
Is it possible to change order of rows in DataTable so for example the one with current index of 5 moves to place with index of 3, etc.?
I have this legacy, messy code where dropdown menu get it's values from DataTable, which get it's values from database. It is impossible to make changes in database, since it has too many columns and entries. My original though was to add new column in db and order by it's values, but this is going to be hard.
So since this is only matter of presentation to user I was thinking to just switch order of rows in that DataTable. Does someone knows the best way to do this in C#?
This is my current code:
DataTable result = flokkurDao.GetMCCHABAKflokka("MSCODE");
foreach (DataRow row in result.Rows)
{
m_cboReasonCode.Properties.Items.Add(row["FLOKKUR"].ToString().Trim() + " - " + row["SKYRING"]);
}
For example I want to push row 2011 - Credit previously issued to the top of the DataTable.
SOLUTION:
For those who might have problems with ordering rows in DataTable and working with obsolete technology that doesn't supports Linq this might help:
DataRow firstSelectedRow = result.Rows[6];
DataRow firstNewRow = result.NewRow();
firstNewRow.ItemArray = firstSelectedRow.ItemArray; // copy data
result.Rows.Remove(firstSelectedRow);
result.Rows.InsertAt(firstNewRow, 0);
You have to clone row, remove it and insert it again with a new index. This code moves row with index 6 to first place in the DataTable.
If you really want randomness you could use Guid.NewGuid in LINQ's OrderBy:
DataTable result = flokkurDao.GetMCCHABAKflokka("MSCODE");
var randomOrder = result.AsEnumerable().OrderBy(r => Guid.NewGuid());
foreach (DataRow row in randomOrder)
{
// ...
}
If you actually don't want randomness but you want specific values at the top, you can use:
var orderFlokkur2011 = result.AsEnumerable()
.OrderBy(r => r.Field<int>("FLOKKUR") == 2011 ? 0 : 1);
You can use linq to order rows:
DataTable result = flokkurDao.GetMCCHABAKflokka("MSCODE");
foreach (DataRow row in result.Rows.OrderBy(x => x.ColumnName))
{
m_cboReasonCode.Properties.Items.Add(row["FLOKKUR"].ToString().Trim() + " - " + row["SKYRING"]);
}
To order by multiple columns:
result.Rows.OrderBy(x => x.ColumnName).ThenBy(x => x.OtherColumnName).ThenBy(x.YetAnotherOne)
To order by a specific value:
result.Rows.OrderBy(x => (x.ColumnName == 2001 or x.ColumnName == 2002) ? 0 : 1).ThenBy(x => x.ColumName)
You can use the above code to "pin" certain rows to the top, if you want more granular than that you can use a switch for example to sort specific values into sorted values of 1, 2, 3, 4 and use a higher number for the rest.
You can not change the order or delete a row in a foreach loop, you should create a new datatable and randomly add the rows to new datatable, you should also track the inserted rows not to duplicate
Use a DataView
DataTable result = flokkurDao.GetMCCHABAKflokka("MSCODE");
DateView view = new DateView(result);
view.Sort = "FLOKKUR";
view.Filter = "... you can even apply an in memory filter here ..."
foreach (DataRowView row in view.Rows)
{
....
Every data table comes with a view DefaultView which you can use, this way you can apply the default sorting / filtering in your datalayer.
public DataTable GetMCCHABAKflokka(string tableName, string sort, string filter)
{
var result = GetMCCHABAKflokka(tableName);
result.DefaultView.Sort = sort;
result.DefaultView.Filter = filter;
return result;
}
// use like this
foreach (DataRowView row in result.DefaultView)
I am having trouble sorting a dataset that is merged in the wrong order. Here is the code:
// Adding new data to DataSet ds:
DataSet dsNew = messageSearcher.Seek(_CriteriaCollection.ToString(), mb.ConvertedClassId, mb.ConnectionString); // Recieving a set of ID that are new and need to be added to ds
ds.Merge(dsNew);
// The data set is now sorted wrongly. Therefore want to sort it based on "MME_ID"
var table = ds.Tables[0];
var view = new DataView(table);
var newRows = view.DeepCopy();
newRows.Sort = "MME_ID DESC"; // <--- This does not sort the ResultSet... Why?
table.Rows.Clear();
foreach (var row in newRows)
table.Rows.Add(row);
ds.AcceptChanges();
What am I doing wrong?
A view is just a view, DataView.Sort will not sort the underlying DataTable. I would suggest to use Linq-To-DataSet instead which is more readable and maintainable:
var table = ds.Tables[0].AsEnumerable()
.OrderByDescending(row => row.Field<int>("MME_ID"))
.CopyToDataTable();
Note that i've presumed that MME_ID is an int column. This throws an exception if its a different type like string. Then you eother have to change the Field<T> to use the proper type or - if you want to order numerically instead of lexicographically - parse it to int with int.Parse.
I've found this piece of code that can be used to get all distinct values. But my datatable has 10 columns. The distinctValues only shows the columns I write in the toTable(); Is it possible to use this function, but also show the rest of the columns?
DataView view = new DataView(table);
DataTable distinctValues = view.ToTable(true, "Column1", "Column2");
Unless those columns you mention are the full key to the table, there is no guarantee that for a particular combination of those two columns the other columns will have exactly one value.
And if they were the key, then there would be no need to use a "distinct" filter.
You can use Linq-To-DataTable
var distinct = from row in table.AsEnumerable()
group row by new
{
Col1 = row.Field<string>("Column1"),
Col2 = row.Field<string>("Column2")
} into Group
select Group.First()
DataTable tblDistinct = distinctRows.CopyToDataTable();
(assuming that you just want an arbitrary row[the first])
Let's say I have a table with a Color column. Color can have various values. I have a C# method that can handle items of a given column at a time. Thus, I would like to :
foreach(colorname in mytable.getDistinctColornames)
monocolorMethod(mytable.getSubTableOnlyContainingRowsWithColor(colorname))
How would I do that elegantly ... ?
At all prices, I would avoid copying the data back & forth. I would like kind of a view on the datatable. A view that would only "show" the rows of a given columns, and a "writable" view (i.e. when I write to the filtered subset, the original table is written to)
EDIT :
Let's say I have a 'Car' Table, and I would like to replace 'Sedan' by 'Truck' in column 'Type' for all cars with 'Color=Red'.
How would I do given the following code ?
DataTable cars (...); // the data
DataView dv = cars.DefaultView;
dv.RowFilter = "Color='Red'";
< Here I would like to loop on the DataView>. The following code does not work :
foreach (row in dv.AsEnumerable)
{
if(row["Type"] == "Sedan")
row["Type"] = "Truck";
}
EDIT 2 :
Found this http://msdn.microsoft.com/fr-fr/library/system.data.dataview.allowedit.aspx which suggests
view.AllowEdit = true;
view[0].BeginEdit();
view[0]["FirstName"] = "Mary";
view[0]["LastName"] = "Jones";
view[0].EndEdit();
Check out this:
Querying DataSets – Introduction to LINQ to DataSet
Did you try using DataView class? It looks like exactly what you want to achieve without using LINQ: http://msdn.microsoft.com/en-us/library/fdcwwhez
An example of usage:
Let say there is a DataTable object named _dt with 4 rows in it:
_dt = new DataTable("") {Columns = {new DataColumn("ID"), new DataColumn("Name"), new DataColumn("Order")}};
_dt.Rows.Add(1, "one", 1);
_dt.Rows.Add(2, "two", 3);
_dt.Rows.Add(3, "three", 2);
_dt.Rows.Add(4, "four", 5);
You can easily create DataView which doesn't filter data but perform sorting operation on it:
_dv = new DataView(_dt, "", "Order, Name", DataViewRowState.CurrentRows);
You can also add new rows into the DataView and because it is set on corresponding DataTable that new row will be added directly to _dt object. The sorting order will be updated as well, and new row won't be the last one within the DataView (because sort is done on Order and Name columns)
var newRow = _dv.AddNew();
newRow["ID"] = 5;
newRow["Name"] = "five";
newRow["Order"] = 4;
newRow.EndEdit();
After that code there will be 5 rows in _dt. Editing rows is also quite simple:
var editedRow = _dv[0];
editedRow.BeginEdit();
editedRow["Name"] = "Test";
editedRow.EndEdit();
You can also use DataView.Find() or DataView.FindRows() methods to find a row within the DataView.
How to get the Selected columns form the DataTable? For e.g my BaseTable has three columns, ColumnA, ColumnB and ColumnC. Now as part of intermediate operations, I need to retrieve all the rows only from the ColumnA. Is there any predefined formula just like DataTable.Select?
DataView.ToTable Method.
DataView view = new DataView(MyDataTable);
DataTable distinctValues = view.ToTable(true, "ColumnA");
Now you can select.
DataRow[] myRows = distinctValues.Select();
From this question: How to select distinct rows in a datatable and store into an array you can get the distinct values:
DataView view = new DataView(table);
DataTable distinctValues = view.ToTable(true, "ColumnA");
If you're dealing with a large DataTable and care about the performance, I would suggest something like the following in .NET 2.0. I'm assuming the type of the data you're displaying is a string so please change as necessary.
Dictionary<string,string> colA = new Dictionary<string,string>();
foreach (DataRow row in table.Rows) {
colA[(string)row["ColumnA"]] = "";
}
return colA.Keys;