Ensure a datatable is ordered by a value - c#

I have a complex algorithm which I am not going to explain here. The code pasted below is doing some processing for each row, but I need to ensure that the table is ordered by a field different than the Primary Key.
I need to do this in this code, not in SQL, or in stored procedures; it needs to be done in .net just before the foreach.
NO LINQ IS ALLOWED, ITS .NET 2.0
THX
Your help is appreciated.
List<int> distinctREFMDossierIds = GetREFMDossierIdsFromBookings();
foreach (int refmDossierId in distinctREFMDossierIds)
{
bool errorsFoundInDetails = false;
bool errorsFoundInHeaders = false;
wingsBookingInterfaceIdswithErrors.Clear();
dicRows.Clear();
sbWingsBookingInterfaceIds= new StringBuilder();
YBooking booking = new YBooking();
foreach (UC090_WingsIntegrationDataSet.WingsBookingInterfaceRow row in _uc090_WingsIntegrationDataSet.WingsBookingInterface.Rows)
{
//code
}

You can use LINQ:
foreach(var row in _uc090_WingsIntegrationDataSet.WingsBookingInterface
.OrderBy(r => r. Something))

You can sort a DataTable like this:
DataTable dt = new DataTable();
dt.DefaultView.Sort = <Sort expression>;
dt = dt.DefaultView.ToTable();

WingsBookingInterface.Rows.OrderBy(item => item.columnName);

You can sort a collection ( for example a List<> ) with the OrderBy extension method.

Related

How to convert a dataset to a list in c#

Is there a way to convert a dataset to a list, there's a lot of example with
datatable but with dataset I have not found.
A Dataset is a collection of DataTables. All you need to do is iterate through each table of the DataSet. This data will typically be different structures, though, so you would want a List for each table.
foreach (var dt in myDataSet.Tables)
{
var list = dt.AsEnumerable()
.Select(dr=> new
{
Name = dr.Field<string>("Name"),
Valuw = dr.Field<string>("Value")
}).ToList();
// do something with your list
}
i think you should use
List<string> list = ds.Tables[0].AsEnumerable().Select(r => r.Field<string>("Name")).ToList();

LINQ result in DataRow

I have an XML for which I have used LINQ to XML. As I wanted to capture some of the element/ attribute data, I have taken them in a string array. Later I have used a foreach loop to insert these values from string array to a DataRow; as my final goal is to get a DataTable out of it.
Following is my code
System.Data.DataTable dt = new System.Data.DataTable();
dt.Columns.Add("col_1");
dt.Columns.Add("col_2");
dt.Columns.Add("col_3");
string[] arr = new string[3];
var myData = from n in doc.Descendants("product")
select new string[]{
arr[0] = n.Attribute("name").Value,
arr[1] = n.Attribute("prodid").Value,
arr[2] = n.Attribute("price").Value
};
foreach (var item in myData)
{
dt.Rows.Add(item[0],item[1],item[2]);
}
Is is possible to combine these and directly get an output as DataTable from LINQ query instead of using foreach?
Instead of select new string[] can I use something like select new DataTable or instance of DataTable?
I understand that my Table structure should be fixed.
Update
Thanks #CodingDawg & #Rahul Singh, I would now like to know the best approach between these two.
I will check for my sample data to compare the same.
But from your experience which one is better considering large data (10000 elements => 10000 rows)?
There is way to load entire XML into DataSet but I guess you need some specific values and also need to do some custom filtering or stuffs thus you are using Linq-to-XML, you can project the datatable directly without using foreach loop like this:-
DataTable myData = doc.Descendants("product")
.Select(x =>
{
var row = dt.NewRow();
row.SetField<string>("col_1", (string)x.Attribute("name"));
row.SetField<string>("col_2", (string)x.Attribute("prodid"));
row.SetField<string>("col_1", (string)x.Attribute("price"));
return row;
}).CopyToDataTable();
myData will hold the resultant dataTable.
Use the Linq .ToList().ForEach() functions
System.Data.DataTable dt = new System.Data.DataTable();
dt.Columns.Add("col_1");
dt.Columns.Add("col_2");
dt.Columns.Add("col_3");
doc.Descendants("product")
.ToList()
.ForEach(
n => dt.Rows.Add(n.Attribute("name").Value,
n.Attribute("prodid").Value,
n.Attribute("price").Value));

Get distinct values from a column of DataTable in .NET 2.0

I am working on a legacy project which was developed using .NET Framework 2.0.
In this project, I get distinct values from DataRowCollection by ItemNo column. I am only interested in ItemNo. The DataRow consist of ItemNo, Qty and Date.
I am thinking of iterating the DataRowCollection and adding the unique ItemNo into a list of string as below (not tested)
var items = new List<string>();
foreach (DataRow orderItem in rows)
{
var itemNo = orderItem["ITEMNO"].ToString().Trim();
if(items.Find(delegate(string str) { return str == itemNo ;}) == null)
{
items.Add(itemNo);
}
}
Is there a better way of doing this without LINQ (.Net Framework 2.0 doesnt like LINQ)
// Given a data table:
var dt = new DataTable();
dt.Columns.Add("ITEMNO");
dt.Rows.Add("1 ");
dt.Rows.Add(" 1");
dt.Rows.Add("2");
var dict = new Dictionary<string, bool>();
foreach(DataRow dr in dt.Rows)
{
var itemNo = dr["ITEMNO"].ToString().Trim();
// Take advantage of O(1) lookup:
if (!dict.ContainsKey(itemNo))
{
dict.Add(itemNo, true);
}
}
// Get list from dictionary keys:
var items = new List<string>(dict.Keys);
If you can install .Net 3.5 on the server, and reference System.Core.dll in your application, you can leverage HashSets which would modify the above code to:
var hashSet = new HashSet<string>();
foreach(DataRow dr in dt.Rows)
{
var itemNo = dr["ITEMNO"].ToString().Trim();
// Only unique elements are added to the hash set,
// no need to check for duplicates
hashSet.Add(itemNo);
}
var items = new List<string>(hashSet);
The benefit of using HashSet over a Dictionary is admittedly trivial, but I'd prefer it since I don't care for the arbitrary bool value in the dictionary, but you'd need to meet the .Net 3.5 and reference requisites.
To get distinct values form a column you can use this method:
List<T> SelectDistict<T>(DataTable table, string column)
{
DataTable temp = new DataView(table).ToTable(true, column);
List<T> items = new List<T>();
foreach (DataRow row in temp.Rows)
items.Add(row.Field<T>(column));
return items;
}
In above method I used DataView.ToTable which by passing true as first argument, selects distinct values.
Here is the usage example:
List<string> items = SelectDistict<string>(yourDataTable, "ITEMNO");
Note
If you need to trim values, you can change above code and first create a clone copy of the DataTable. Then add a computed column which contains, trimmed value from the given column name for distinct values by assigning TRIM(column) to Expression property of column. Then follow the steps using the new trimmed column like above code.

dynamic datatable sorting in ascending or descending

I have created dynamic table
DataTable date = new DataTable();
date.Columns.Add("date1");
and made fill the column name "date1" with date as
date1(Column name)
05-07-2013
10-07-2013
09-07-2013
02-07-2013
and made fill my dynamic table
Now i want this dynamic table data to be sort as ascending or descending order
For eg:
date1(Column name)
02-07-2013
05-07-2013
09-07-2013
10-07-2013
This cannot be done with the original data table. However you can create a new, sorted one:
DataView view = date.DefaultView;
view.Sort = "date1 ASC";
DataTable sortedDate = view.ToTable();
You can use DataTable.Select(filterExpression, sortExpression) method.
Gets an array of all DataRow objects that match the filter criteria,
in the specified sort order.
date.Select("", "YourColumn ASC");
or
date.Select("", "YourColumn DESC");
As an alternative, you can use DataView like;
DataView view = date.DefaultView;
view.Sort = "YourColumn ASC";
DataTable dt = view.ToTable();
Thought I would give in my two cents here. Instead of using a sorting algorithm which takes time and computational performance, why not instead reverse the way in which you are adding data to your data object.
This won't work for everyone's scenario - but for my own it worked out perfectly.
I had a database which listed items in an ascending order, but or ease of use I needed to reverse the way in which people could see the data (DESC) so that the newest input shows at the top, rather then the bottom of the list.
So, I just changed my for loop so instead of working from 0 -> upwards, it started from the length of the datatable (-1 to stop an overflow) and then stops when it is >= to 0;
private Dictionary<string, string> GetComboData(string table, int column, bool id, int idField = 0)
{
SqlClass sql = new SqlClass(database);
Dictionary<string, string> comboBoxData = new Dictionary<string, string>();
if (sql.connectedToServer)
{
sql.SelectResults(SQLCommands.Commands.SelectAll(table));
for (int i = sql.table.Rows.Count-1; i >= 0; i--)
{
string tool = sql.table.Rows[i].ItemArray.Select(x => x.ToString()).ToArray()[column];
string ID = sql.table.Rows[i].ItemArray.Select(x => x.ToString()).ToArray()[idField];
comboBoxData.Add(ID, tool);
}
}
return comboBoxData;
}
using OrderByDescending()
#foreach (var rca in Model.OrderByDescending(x=>x.Id))
{
<tr class="heading">
<td>#rca.PBINo</td>
<td>#rca.Title</td>
<td>#rca.Introduction</td>
<td>#rca.CustomerImpact</td>
<td>#rca.RootCauseAnalysis</td>
</tr>
}

Can I use Linq to project a new typed datarow?

I currently have a csv file that I'm parsing with an example from here:
http://alexreg.wordpress.com/2009/05/03/strongly-typed-csv-reader-in-c/
I then want to loop the records and insert them using a typed dataset xsd to an Oracle database.
It's not that difficult, something like:
foreach (var csvItem in csvfile)
{
DataSet.MYTABLEDataTable DT = new DataSet.MYTABLEDataTable();
DataSet.MYTABLERow row = DT.NewMYTABLERow();
row.FIELD1 = csvItem.FIELD1;
row.FIELD2 = csvItem.FIELD2;
}
I was wondering how I would do something with LINQ projection:
var test = from csvItem in csvfile
select new MYTABLERow {
FIELD1 = csvItem.FIELD1,
FIELD2 = csvItem.FIELD2
}
But I don't think I can create datarows like this without the use of a rowbuilder, or maybe a better constructor for the datarow?
You could, but you shouldn't. NewRow() is a method, not a constructor that allows for an object initializer to be used. You're better off sticking with the foreach loop for clarity.
You can abuse LINQ to pull this off, but this is not recommended and is for demonstration purposes only:
DataTable dt = new DataTable();
dt.Columns.Add("Id", typeof(int));
dt.Columns.Add("Customer", typeof(string));
dt.Rows.Add(new Object[] { 24, "Peter Parker" });
dt.Rows.Add(new Object[] { 42, "Bruce Wayne" });
var query = Enumerable.Range(1, 5).All(i =>
{
var row = dt.NewRow();
row["Id"] = i;
row[1] = "Customer" + i;
dt.Rows.Add(row);
return true;
});
foreach (DataRow row in dt.Rows)
{
Console.WriteLine("{0}: {1}", row[0], row[1]);
}
The idea is to use a lambda statement to do your work. Notice you gain nothing and the statements are going to be identical to what you had in the foreach loop. On top of that, LINQ is deferred, so the rows are never added until the query is iterated over. In the snippet above I forced this to be immediate by using the All method and returning true for each item so all items continue to be processed. In fact the var query = bit can be removed since it's not used.
In your case your source would be the csvfile:
csvfile.All(csvItem => { /* do work here */ });
This approach introduces side effects since the LINQ query isn't used for its original intent. LINQ is for querying. You might also find Eric Lippert's post helpful: "foreach" vs "ForEach".

Categories

Resources