dynamic datatable sorting in ascending or descending - c#

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>
}

Related

How to get data as IEnumerable<MODEL> from DataTable by using LINQ?

I have a DataTable with some attributes data get from a database, each data in that DataTable belong to a product, and each product could have more than one attribute.
So i have another DataTable which has all the products in a foreach by looping through each row i'm adding each product to it's List<Plu> like this:
var productAttr = new List<Plu.Attributi>();
foreach (DataRow rowPlu in dt.Rows)
{
try
{
int id = (int)rowPlu["ID_PLUREP"];
plu.Add(new Plu(
id,
(string)rowPlu["CODICE_PRP"],
(string)rowPlu[ESTESA],
(string)rowPlu[DESCR], (float)rowPlu["PRE_PRP"],
rowPlu.IsNull("IMG_IMG") ? null : (string)rowPlu["IMG_IMG"],
productAttr,
null,
(int)rowPlu["ID_MENU_PRP"]
));
}
catch
{
return plu;
}
}
For now the productAttr is empty but now i need to add to each product it's attributes, so with the following function i get a DataTable filled with data from database with all product attributes:
var attributi = Attributi(connection, idNegozio);
and then i was trying to do something like this inside the foreach
foreach (DataRow rowPlu in dt.Rows)
{
try
{
int id = (int)rowPlu["ID_PLUREP"];
plu.Add(new Plu(
id,
(string)rowPlu["CODICE_PRP"],
(string)rowPlu[ESTESA],
(string)rowPlu[DESCR], (float)rowPlu["PRE_PRP"],
rowPlu.IsNull("IMG_IMG") ? null : (string)rowPlu["IMG_IMG"],
from row in attributi.AsEnumerable() where row.Field<int>("ID_PLUREP_VAT") == id select row,
null,
(int)rowPlu["ID_MENU_PRP"]
));
}
catch
{
return plu;
}
}
But the LINQ returns a EnumerableRowCollection while i need a IEnumerable<Plu.Attribute>, so i was wondering if there is a lazy way to cast the .AsEnumerable to IEnumerable<Plu.Attrbute>...
The problem is, that the DataTable only knows which values are in the cells. It does not know what these values stand for. It does not know that the number in column 0 is in fact an Id. It doesn't know that the string in column 1 is the Name of a Customer, and the DateTime in column 2 is the Birthday of the Customer.
If you will be using the contents of this Datatable (or similar DataTables) for other queries in the future, you need some translation from DataRow to the items that they stand for.
Once you've got the translation from DataRow to Plu, you can convert your DataTable to an IEnumerable<Plu>, and do other LINQ processing on it.
Usage will be like:
DataTable table = ...
var mySelectedData = table.AsEnumerable().ToPlus()
.Where(plu => ...)
.Select(plu => new {...})
.ToList();
You need two extension methods: one that converts a DataRow to a Plu and one that converts a sequence of DataRows to a sequence of Plus. See extension methods demystified
public static Plu ToPlu(this DataRow row)
{
// TODO implement
}
public static IEnumerable<Plu> ToPlus(this IEnumerable<DataRow> dataRows)
{
// TODO: exception if null dataRows
return dataRows.Select(row => row.ToPlu());
}
If desired, create an extension method from DataTable to extract the Plus:
public static IEnumerable<Plu> ExtractPlus(this DataTable table)
{
// TODO: exception if table null
return table.AsEnumerable().ToPlus();
}
Usage:
DataTable table = ...
IEnumerable<Plu> plus = table.ExtractPlus();
I haven't got the faintest idea what a Plu is, and you forgot to mention the relevant properties of the Plu, so I'll give you an example of a table that contains Customers:
class Customer
{
public int Id {get; set;} // Id will be in column 0
public string Name {get; set;} // Name will be in column 1
...
}
public static Customer ToCustomer(this DataRow row)
{
return new Customer
{
Id = (int)row[0],
Name = (string)row[1],
};
}
If desired, instead of columnIndex you can use the name of the column.
So by only creating a ToPlu, and a one-liner method to convert sequences of DataRows to a sequence of Plus, you've extended LINQ with your methods to read your tables.
To be on the safe side, consider creating an extension method that converts a sequence of Plus to a DataTable. This way, the layout of the table is in one location: ToPlu(DataRow) and ToDataRow(Plu). Future changes in the table layout will be easier to manage, users of your DataTable will only think in sequences of Plus.
You can do something like below. If you want IEnumerable<Plu> you can remove the .ToList() from the end.
dt.AsEnumerable().Select(x => new Plu {
Id = x.Field<int>("ID_PLUREP"),
CodicePrep = x.Field<string>("CODICE_PRP"),
....
Attributes = attributi.AsEnumerable()
.Where(y => y.Field<int>("ID_PLUREP_VAT") == x.Field<int>("ID_PLUREP"))
.Select(z => new Attributi
{
....
}).ToList(),
....
}).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.

Compare two datatables to find matching values

I have 2 data tables. Each one has one column and I want to compare them and get same values on them but it does not work.
This is my code:
string CurrentRequestUrl = (HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.ToString());
DataTable dt_Item = ERP.BLL_Menu_Item.Custom_Item_ID(CurrentRequestUrl);
DataTable dt2_SysRole = ERP.BLL_Sys_User_Role.Custom_Role(Convert.ToInt64(App.UserID));
var dtOne = (dt_Item.AsEnumerable()).ToList();
var dtTwo = (dt2_SysRole.AsEnumerable()).ToList();
IEnumerable<DataRow> objIntersectResult = ((dtOne).Intersect((dtTwo))).ToList();
How can I find the matching values?
Intersect does not work here because on DataRow it just compares references. Because all rows are different references you get an empty list. Instead you want to compare values. Therefore you can use Join. But which row do you want to return from both tables? If you want both rows you could create an anonymous type of both:
var objJoinResult = from rowItem in dt_Item.AsEnumerable()
join rowSysRole in dt2_SysRole.AsEnumerable()
on rowItem.Field<string>("ColumnName") equals rowSysRole.Field<string>("ColumnName")
select new { rowItem, rowSysRole };
Output:
foreach (var both in objJoinResult)
{
Console.WriteLine("rowItem:{0} rowSysRole:{1}",
string.Join(",", both.rowItem.ItemArray),
string.Join(",", both.rowSysRole.ItemArray));
}

Ensure a datatable is ordered by a value

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.

Categories

Resources