Cannot sort DDL using multiple fields in asp.net - c#

I am trying to sort a dynamically created DDL. This DDL has a combination of fields being Location1, Location2, Location3.
The code used to create the DDL is as follows:
ddlLocation.Items.Clear();
dtLocation = dataSource.GetFilteredRiskInfo("location");
ddlLocation.Items.Insert(0, new ListItem("All", "-1"));
foreach (DataRow row in dtLocation.Rows)
{
if (this.ddlLocation.Items.FindByText(row["Location1"].ToString()) == null)
this.ddlLocation.Items.Add(new ListItem(row["Location1"].ToString()));
if (this.ddlLocation.Items.FindByText(row["Location2"].ToString()) == null)
this.ddlLocation.Items.Add(new ListItem(row["Location2"].ToString()));
if (this.ddlLocation.Items.FindByText(row["Location3"].ToString()) == null)
this.ddlLocation.Items.Add(new ListItem(row["Location3"].ToString()));
}
The following code works for location1 (I think).
[DisplayColumn("location","Location1")]
public partial class Location
{
}
I have been researching how to add multiple fields ie: location2 & location3, it does not work. The code itself shows an error for Location1 & Location2 ("The name 'Location1' does not exist in the current context")
[DisplayColumn("location","SortColumn")]
public partial class Location
{
public string SortColumn
{
get { return Location1 + Location2; }
}
}
All help will be much apprecaited.
The list of locations need to be as follows. Say the locations have the following data.
Location1:
Sydney, Wollongong Perth
Location2:
Adelaide, Northern Territory
Location3:
Brisbane, Canberra, Hobart
I need the combined list to look as follows:
Adelaide
Brisbane
Canberra
Hobart
Northern Territory
Perth
Sydney
Wollongong
My code now looks as follows:
ddlLocation.Items.Clear();
// new table to combine the 3 columns of dtLocation into a one column datatable
DataTable sortedDt = new DataTable();
dtLocation = dataSource.GetFilteredRiskInfo("location");
sortedDt.Columns.Add("Location");
// combining columns
foreach (DataRow row in dtLocation.Rows)
{
sortedDt.Rows.Add(row["Location1"]);
sortedDt.Rows.Add(row["Location2"]);
sortedDt.Rows.Add(row["Location3"]);
}
// now sort these now that they're all in the same column
sortedDt.DefaultView.Sort = "Location";
sortedDt = sortedDt.DefaultView.ToTable(); // should be the new sorted table
// now your original code, but modified to populate the ddl with the new sorted data
ddlLocation.Items.Insert(0, new ListItem("All", "-1"));
foreach (DataRow row in sortedDt.Rows)
{
this.ddlLocation.Items.Add(new ListItem(row["Location"].ToString()));
}
Now the list is in alphabetical order but has duplicate entries. I need to be able to remove the duplicates/make the entries distinct.

Not only should you presort it in GetFilteredRiskInfo as FrankO suggests, but it sounds like you have to combine the 3 location columns into one. If you can do that in GetFilteredRiskInfo it might be cleaner, if not you can try combining the columns and sorting in code with something like this:
// new table to combine the 3 columns of dtLocation into a one column datatable
DataTable sortedDt = new DataTable();
sortedDt.Columns.Add("Location");
// combining columns
foreach (DataRow row in dtLocation.Rows)
{
sortedDt.Rows.Add(row["Location1"]);
sortedDt.Rows.Add(row["Location2"]);
sortedDt.Rows.Add(row["Location3"]);
}
// now sort these now that they're all in the same column
sortedDt.DefaultView.Sort = "Location";
sortedDt = sortedDt.DefaultView.ToTable(); // should be the new sorted table
// now your original code, but modified to populate the ddl with the new sorted data
ddlLocation.Items.Clear();
dtLocation = dataSource.GetFilteredRiskInfo("location");
ddlLocation.Items.Insert(0, new ListItem("All", "-1"));
foreach (DataRow row in sortedDt.Rows)
{
this.ddlLocation.Items.Add(new ListItem(row["Location"].ToString()));
}

Thanks both FronkO (I now have sorted lists on all my drop downs) and madamission (for the extra help with the locations sorting). Between the 2 of you and some help from the internet I now have it working. The working code is as follows:
//Location
ddlLocation.Items.Clear();
// new table to combine the 3 columns of dtLocation into a one column datatable
DataTable sortedDt = new DataTable();
sortedDt.Columns.Add("Location");
dtLocation = dataSource.GetFilteredRiskInfo("location");
// combining columns
foreach (DataRow row in dtLocation.Rows)
{
sortedDt.Rows.Add(row["Location1"]);
sortedDt.Rows.Add(row["Location2"]);
sortedDt.Rows.Add(row["Location3"]);
}
// now make them distinct & sort them now that they're all in the same column
sortedDt = sortedDt.DefaultView.ToTable(/*distinct*/ true);
sortedDt.DefaultView.Sort = "Location";
sortedDt = sortedDt = sortedDt.DefaultView.ToTable();
// now your original code, but modified to populate the ddl with the new sorted data
ddlLocation.Items.Insert(0, new ListItem("All", "-1"));
foreach (DataRow row in sortedDt.Rows)
{
this.ddlLocation.Items.Add(new ListItem(row["Location"].ToString()));
}

Related

Prevent duplicate item from being added to a GridView using ASP.NET C#

I have this code for adding items into gridview. But in my below code duplicate items are not added. I need distinct items with no duplicate entries.
Below is my .cs code.
private DataTable list(String dbObject, String filterName, String filterValue,string PositonId,string Status)
{
NameValuePairList objNameValuePairList = new NameValuePairList();
objNameValuePairList.Add(new NameValuePair("#FilterValue", filterValue, PositonId, Status));
objNameValuePairList.Add(new NameValuePair("#Action", "FilterBy" + filterName, PositonId, Status));
DataTable dt = dl.Search_RegisterationInfo(dbObject, objNameValuePairList, PositonId, Status);
return dt;
}
public DataTable list(String dbOject, FilterList myFilterList,string PositonId,string Status)
{
// gets a collection(dataset) of all unique filters(datatables) and also group all subfilters(rows) under each filter
DataTable dt;
DataSet ds = new DataSet();
// a filter may be a Nationality or a Qualification
foreach (Filter item in myFilterList)
// a subfilter may be Indian or Expatriate under the filter Nationality
{
// another subfilter may be Bachelor degree or Master Degree under the filter Qualification
dt = list(dbOject, item.getFilterName, item.getFilterValue, PositonId,Status);
dt.TableName = item.getFilterName;
// datatables are named based on the filters
if (ds.Tables.Count == 0)
// so we get a collection of unique filters (datatables) in the dataset
ds.Tables.Add(dt);
// add new filter without checking, since for the first time, no conflicts are possible
else
{
bool tableMatchFound = false;
foreach (DataTable newdt in ds.Tables)
if (newdt.TableName == dt.TableName)
{
// see if filter is already present in the dataset
tableMatchFound = true;
// when the current filter is already present in the dataset
foreach (DataRow dr in dt.Rows)
ds.Tables[newdt.TableName].ImportRow(dr);
}
// importrow() adds distinct new subfilters to the existing filter, duplicate items are not added
if (!tableMatchFound)
ds.Tables.Add(dt);
}
// if the filter does not exist, add the new filter to the collection
}
// the entire collection of filters will contain duplicate items
// distinct items from the entire collection is filtered out in the next section
dt = ds.Tables[0].Clone();
// get the structure of the first filter as they all apply to the same table object
if (ds.Tables.Count == 1)
dt = ds.Tables[0];
// if there is only one filter, no filtering is required
else
// if there are more than one, compare each subfilter of every other filter with the subfilters of the first filter
foreach (DataRow dr in ds.Tables[0].Rows)
{
// each subfilter from the first filter is used as a pivot
int rowMatchFound = 1;
for (int i = 1; i < ds.Tables.Count; i++)
// search all filters except the first one
foreach (DataRow newdr in ds.Tables[i].Rows)
// select each subfilter from all the filter
if ((int)dr["RegistrationId"] == (int)newdr["RegistrationId"])
rowMatchFound++;
if (rowMatchFound == ds.Tables.Count)
// a match is found exactly once in all the filters
dt.ImportRow(dr);
// the final item is selected so that is is present in all the filters
}
return dt;
}
For more details, I am using below example code:
http://www.codeproject.com/Tips/773362/Filtering-search-results-with-multiple-CheckBox-Li
There is an above comment line saying clearly in my question like:
// importrow() adds distinct new subfilters to the existing filter, duplicate items are not added
Thank you in advance

How to Create sub DataTable from an existing DataTable

I have a DataTable(dataTable1) that have 25-30 columns. I want to bind a DataGridView by creating a small DataTable (dataTable2) that will have few columns (may 5-10) from the existing DataTable.
So my main task is to create a DataTable with fewer columns from the existing one.
Here is the code what I have tried so for..
DataTable subDataTable()
{
DataTable smallTable=new DataTable();
smallTable =dataTable1;// dataTable1 is already filled with data
smallTable.Columns.Remove("Column2");
smallTable.Columns.Remove("Column5");
smallTable.Columns.Remove("Column6");
smallTable.Columns.Remove("Column13");
smallTable.Columns.Remove("Column16");
return smallTable;
}
Its working fine. But I'm looking if there any better way.
You can try to convert your DataTable to IEnumerable,and Select necessary fields with linq like this:
var myValues = dataTable1.AsEnumerable()
.Select(x => new { col1 = x["Column1"], col2 = x["Column2"]..});
dataGridView.DataSource = myValues;
Your code will not work because you all you do is assign a variable smallTable with reference to dataTable1 and you removing columns from your original table object
Linq is faster to write but here is what you want to do to understand your issue:
DataTable smallTable = dataTable1.Clone(); // Copy data structure
// Now you can remove your columns
smallTable.Columns.Remove("Column2");
......
foreach (var row in dataTable1.Rows) // iterate all rows
{
var newRow = smallTable.NewRow();
foreach (var col in smallTable.Columns) // and iterate only needed columns
{
newRow[col.ColumnName] = row[col.ColumnName];
}
}
This is pretty much what sugar-coated by Linq
DataView dv = new DataView(dataTable1);
DataTable smallTable = dv.ToTable(true, new string[] { "Column2", "Column5"...});
https://social.msdn.microsoft.com/Forums/en-US/ac2c7c95-66d6-4db6-a6fb-4dccd5fa701e/is-there-a-better-way-to-get-subtable-with-selected-columns-of-a-datatable?forum=adodotnetdataset
Tomer.

How to filter a specific value from a data table

I have five rows in my data table (with column AccountId, Name, Email, Address) and I want to get a specific row on basis of AccountId as all the five rows have different AccountID. I want to filter it on the basis of AccountID. I mean I only need one row from the Data table to process on the basis of AccountId.
How do I get a specfic row from the data table containing the AccountId that I have passed?
Three options:
Use DataTable.Select, providing a filter expression
Iterate over the rows yourself
Use LINQ, with the data table extensions
Personally I'd suggest using the last option (LINQ):
var row = table.AsEnumerable()
.FirstOrDefault(r => r.Field<string>("AccountID") == accountID);
if (row != null)
{
// Use the row
}
Have you looked into the DataTable.Select() method?
http://msdn.microsoft.com/en-us/library/system.data.datatable.select(v=vs.100).aspx
public class DataTableExample
{
public static void Main()
{
//adding up a new datatable
DataTable dtEmployee = new DataTable("Employee");
//adding up 3 columns to datatable
dtEmployee.Columns.Add("ID", typeof(int));
dtEmployee.Columns.Add("Name", typeof(string));
dtEmployee.Columns.Add("Salary", typeof(double));
//adding up rows to the datatable
dtEmployee.Rows.Add(52, "Human1", 21000);
dtEmployee.Rows.Add(63, "Human2", 22000);
dtEmployee.Rows.Add(72, "Human3", 23000);
dtEmployee.Rows.Add(110,"Human4", 24000);
// sorting the datatable basedon salary in descending order
DataRow[] rows= dtEmployee.Select(string.Empty,"Salary desc");
//foreach datatable
foreach (DataRow row in rows)
{
Console.WriteLine(row["ID"].ToString() + ":" + row["Name"].ToString() + ":" + row["Salary"].ToString());
}
Console.ReadLine();
}
}
Example with an array:
http://msdn.microsoft.com/en-us/library/f6dh4x2h(VS.80).aspx
Example with a single Object:
http://msdn.microsoft.com/en-us/library/ydd48eyk
Just use something like this:
DataTable dt = new DataTable();
DataRow dr = dt.Rows.Find(accntID);
Hope this helped you out.

Delete row from datatable where first column does not contain (some string)

I have DataTable with the following columns:
ClientID date numberOfTransactions price
ClientID is of type string and I need to ensure that its contents include "A-" and "N6" for every value in the table.
I need to delete all rows from the DataTable where this first column (ClientID) does not contain both "A-" and "N6" (some totals and other unnecessary data). How can I select and delete these rows specifically from the DataTable?
I know this:
foreach (DataRow row in table.Rows) // Loop over the rows.
{
//Here should come part "if first column contains mentioned values
}
I also know this
If (string.Contains("A-") == true && string.Contains("N6") == true)
{
//Do something
}
I need help how to implement this for first column of each row.
Try this:
EDIT: Totally messed up that last line, so if you tried it, try it now that I made it not stupid. =)
List<int> IndicesToRemove = new List<int>();
DataTable table = new DataTable(); //Obviously, your table will already exist at this point
foreach (DataRow row in table.Rows)
{
if (!(row["ClientID"].ToString().Contains("A-") && row["ClientID"].ToString().Contains("N6")))
IndicesToRemove.Add(table.Rows.IndexOf(row));
}
IndicesToRemove.Sort();
for (int i = IndicesToRemove.Count - 1; i >= 0; i--) table.Rows.RemoveAt(IndicesToRemove[i]);
try using this,
assuming dt as your Datatabe object and ClientID as your first column (hence using ItemArray[0])
for(int i=0; i<dt.Rows.Count; i++)
{
temp = dt.Rows[i].ItemArray[0].ToString();
if (System.Text.RegularExpressions.Regex.IsMatch(temp, "A-", System.Text.RegularExpressions.RegexOptions.IgnoreCase) || System.Text.RegularExpressions.Regex.IsMatch(temp, "N6", System.Text.RegularExpressions.RegexOptions.IgnoreCase))
{
dt.Rows.RemoveAt(i);
i--;
}
}
Simple and straight forward solution... hope it helps
this should be more efficient, both in lines of Code and Time, try this :)
for(int x=0; x<table.Rows.Count;)
{
if (!table.Rows[x].ItemArray[0].contains("A-") && !table.Rows[x].ItemArray[0].contains("N6"))
table.Rows.RemoveAt(x);
else x++;
}
Happy Coding
Preface: C.Barlow's existing answer is awesome, this is just another route someone could take.
This is one way to do it where you never have to loop all the way through the original table (by taking advantage of the DataTable.Select() method):
DataTable table = new DataTable(); // This would be your existing DataTable
// Grab only the rows that meet your criteria using the .Select() method
DataRow[] newRows = table.Select("ClientID LIKE '%A-%' AND ClientID LIKE '%N6%'");
// Create a new table with the same schema as your existing one.
DataTable newTable = table.Clone();
foreach (DataRow r in newRows)
{
// Dump the selected rows into the table.
newTable.LoadDataRow(r.ItemArray, true);
}
And now you have a DataTable with only the rows you want. If necessary, at this point you could clear out the original table and replace it with the contents of the new one:
table.Clear();
table = newTable.Copy();
Edit: I thought of a memory optimization last night, you can just overwrite the existing table once you have the rows you need, which avoids the need for the temporary table.
DataTable table = new DataTable(); // This would be your existing DataTable
// Grab only the rows that meet your criteria using the .Select() method
DataRow[] newRows = table.Select("ClientID LIKE '%A-%' AND ClientID LIKE '%N6%'");
// Clear out the old table
table.Clear();
foreach (DataRow r in newRows)
{
// Dump the selected rows into the table.
table.LoadDataRow(r.ItemArray, true);
}

Remove duplicate column values from a datatable without using LINQ

Consider my datatable,
Id Name MobNo
1 ac 9566643707
2 bc 9944556612
3 cc 9566643707
How to remove the row 3 which contains duplicate MobNo column value in c# without using LINQ. I have seen similar questions on SO but all the answers uses LINQ.
The following method did what i want....
public DataTable RemoveDuplicateRows(DataTable dTable, string colName)
{
Hashtable hTable = new Hashtable();
ArrayList duplicateList = new ArrayList();
//Add list of all the unique item value to hashtable, which stores combination of key, value pair.
//And add duplicate item value in arraylist.
foreach (DataRow drow in dTable.Rows)
{
if (hTable.Contains(drow[colName]))
duplicateList.Add(drow);
else
hTable.Add(drow[colName], string.Empty);
}
//Removing a list of duplicate items from datatable.
foreach (DataRow dRow in duplicateList)
dTable.Rows.Remove(dRow);
//Datatable which contains unique records will be return as output.
return dTable;
}
As you are reading your CSV file ( a bit of pseudo code, but you get the picture ):
List<String> uniqueMobiles = new List<String>();
String[] fileLines = readYourFile();
for (String line in fileLines) {
DataRow row = parseLine(line);
if (uniqueMobiles.Contains(row["MobNum"])
{
continue;
}
uniqueMobiles.Add(row["MobNum"]);
yourDataTable.Rows.Add(row);
}
This will only load the records with unique mobiles into your data table.
This is the simplest way .
**
var uniqueContacts = dt.AsEnumerable()
.GroupBy(x=>x.Field<string>("Email"))
.Select(g=>g.First());
**
I found it in this thread
LINQ to remove duplicate rows from a datatable based on the value of a specific row
what actually was for me that I return it as datatable
DataTable uniqueContacts = dt.AsEnumerable()
.GroupBy(x=>x.Field<string>("Email"))
.Select(g=>g.First()).CopyToDataTable();
You might want to look up the inner workings on DISTINCT before running this on your sharp DB (be sure to back up!), but if it works as I think it does (grabbing the first value) you should be able to use (something very similar to) the following SQL:
DELETE FROM YourTable WHERE Id NOT IN (SELECT DISTINCT Id, MobNo FROM YourTable);
You can use "IEqualityComparer" in C#

Categories

Resources