HowTo reorder items in DataView object - c#

I have a DataView object with productID and productName,
i get all items from Products Table and store them in Cache.
I want to get items that user bought in order he bought them without using another query or joining tables.
ie.
Products DataView
1. Foo
2. Foo2
3. Foo3
Filtering to ProductsBoughtByUser using RowFilter (productID in (1,3))
UserProducts DataView
1.Foo
3.Foo3
Now user first bought Foo3, how do i reorder items based on correct ( chronological ) Array. ie 3 1
Thanks

Here is the syntax for DataView.Sort:
private void SortByTwoColumns()
{
// Get the DefaultViewManager of a DataTable.
DataView view = DataTable1.DefaultView;
// By default, the first column sorted ascending.
view.Sort = "State, ZipCode DESC";
}
From your original post, it sounds like you only have Product ID and Product Name. You can't sort these in memory unless you're also retrieving a purchase/order date.
Probably the easiest thing to do would be to add the date column (PurchaseDate) to your sql statement that you're already using, then do a view.Sort = "PurchaseDate DESC";
That way, you don't have to write another statement or hit the database a second time for this sort.
Edit:
The DataRowView has integral and string indexers. e.g.:
foreach (DataRowView row in dataView)
{
var value = row["COLUMN_NAME"];
}
The column is stored as an object, so you'll have to check for null and convert to your data type

Related

Avoid duplication in DataTable query and build

What would be the right way to avoid duplication when querying datatable and then saving it to DataTable. I'm using the pattern below, which gets very error-prone once tables grow. I looked at below hints. With first one copyToDataTable() looks not really applicable and second is for me much too complex for the task. I would like to split the below code into 2 separate methods (first to build the query and second to retrieve the DataTable). Perhaps if I avoid the anonymous type in the query this should be easier to avoid hardcoding all the column names - but I'm somehow lost with this.
Filling a DataSet or DataTable from a LINQ query result set
or
https://msdn.microsoft.com/en-us/library/bb669096%28v=vs.110%29.aspx
public DataTable retrieveReadyReadingDataTable()
{
DataTable dtblReadyToSaveToDb = RetrieveDataTableExConstraints();
var query = from scr in scrTable.AsEnumerable()
from products in productsTable.AsEnumerable()
where(scr.Field<string>("EAN") == products.Field<string>("EAN"))
select
new
{
Date = DateTime.Today.Date,
ProductId = products.Field<string>("SkuCode"),
Distributor = scr.Field<string>("Distributor"),
Price = float.Parse(scr.Field<string>("Price")),
Url = scr.Field<string>("Url")
};
foreach (var q in query)
{
DataRow newRow = dtblReadyToSaveToDb.Rows.Add();
newRow.SetField("Date", q.Date);
newRow.SetField("ProductId", q.ProductId);
newRow.SetField("Distributor", q.Distributor);
newRow.SetField("Price", q.Price);
newRow.SetField("Url", q.Url);
}
return dtblReadyToSaveToDb;
}
Firstly, you have to decide what "duplicate" means in your case. According to your code i would say a duplicate is a row with the same value in column Date, ProductId and Distributor. So add a multi column primary key for those columns first.
Secondly, you should add some sort of code that first queries existing rows and then compares these existing rows to the rows you want to create. If a match is found, then simply just don't insert a new row.

c# DataView& DataGridView sorting

I have a small problem. I need to sort data in the DataGridView (WinForms application) in descending order. I apply a DataView as DataSource to myGrid:
DataView view = myDataTable.DefaultView;
view.Sort = "id DESC";
myGrid.DataSource = view;
id column is string data type, and is in ##/yy format. First part is incrementing integer, second part (after '/') is last two digits of current year. Unfortunately it has to be in this format.
After sortting it returns in this order:
9/14,8/14,7/14,6/14,5/14,4/14,3/14,2/14,10/14,1/14...
But it should be like this:
10/14,9/14,8/14,7/14,6/14,...
What would be the easiest way to solve this?
Thank you.
EDIT:
Added some more info...
You have a few options here. You can clone your table and modify the type and typecast it properly by modifying the values directly, or you can use a helper column, etc. This can be accomplished many ways. I'll give you a simple example that uses a single helper column to process the string into a date then sort in that way.
If you have some integer (I'll use a 16-bit integer as the type) and a two-digit year separated by a /, we can write it instead as follows:
// Setup a sample table to match yours
DataTable myDataTable = new DataTable();
myDataTable.Columns.Add("id", typeof(string));
// Add some values to the table
myDataTable.Rows.Add("7/14");
myDataTable.Rows.Add("4/14");
myDataTable.Rows.Add("8/14");
myDataTable.Rows.Add("3/14");
myDataTable.Rows.Add("6/14");
myDataTable.Rows.Add("10/14");
myDataTable.Rows.Add("5/14");
myDataTable.Rows.Add("2/14");
myDataTable.Rows.Add("9/14");
myDataTable.Rows.Add("1/14");
// Add a helper column with 16-bit format based on the values in id
myDataTable.Columns.Add("helper", typeof(Int16));
// Convert the value in the id column of each row to a string,
// then split this string at the '/' and get the first value.
// Convert this new value to a 16-bit integer,
// then save it in the helper column.
foreach (DataRow row in myDataTable.Rows) row["helper"] =
Convert.ToInt16(row["id"].ToString().Split('/')[0]);
// Create a view to match yours, sorting by helper column instead of id
DataView view = myDataTable.DefaultView;
view.Sort = "helper DESC";
//myGrid.DataSource = view;
// Write the output from this view
foreach (DataRow row in view.ToTable().Rows) Console.WriteLine(row["id"]);
which produces the output...
10/14
9/14
8/14
7/14
6/14
5/14
4/14
3/14
2/14
1/14
If you need to sort by year as well, you can add an additional helper column in the same manner.

Querying data from SQL

I need to query a table from database which has 400 rows and 24 columns. I need to query this table so that on each row and then on each column of row I can perform some C# code ( I can use column information to execute some code).
Now at the moment I am querying each row again and again from table using select statement and storing to a custom list and performing custom operations on it.
Is it best and fastest way of doing it ? or should I just query the whole table one time and store somewhere ? not sure where in a dataset and then run throw custom code to do some operation using information in each row ?
You can fetch the table from database once and store it in datatable and then just use linq to select the column something like this
var data = dt.AsEnumerable().Select(s => s.Field<string>("myColumnName")).ToArray<string>();
and If you don't want to use other columns anywhere in your code then you should select only useful column from the database.
You can also select multiple columns of a database using linq. The values will be stored in anonymous type of object.
var mutipleData = from row
in dt.AsEnumerable()
select new
{ Value1 = row["Column1"].ToString(),
Value2 = row["Column2"].ToString()
};
Assuming that each field is 1000 bytes, the total memory to hold your 400 rows would be 9.6MB. Peanuts! Just read the whole table in a DataTable and process it as you wish.
Select all the records from DB table which are f your concern
Copy the select records into DataTable.
Pseudo Code:
--dt is datatable
foreach(datarow dr in dt.rows)
{
--perform operation
string str=dr["columnname"].tostring
}
400 rows isn't a massive amount, however it depends on the data in each column and how often you are likely to run the query. If all you are going to do is run the query and manipulate the output, use a DataReader instead.
If it's only 400 records, I'd fetch them all at once, store them in a class and iterate over each instance.
Something like:
Class
public class MyTableClass(){
string property1 {get; set;}
string property2 {get; set;}
int property3 {get; set;}
// etc.
}
Logic:
ICollection<MyTableClass> lstMyTableClass = (
from m in db.mytableclass
select m
).ToList();
return lstMyTableClass;
And then a loop:
foreach(var myTableInstance in lstMyTableClass){
myTableInstance.DoMyStuff();
}
If the number of records will always be below thoussand, just query all the records and keep it in a List.
Once the data is in the List you can query the List n number of times using LINQ without hitting the database for each request.

Last Row of Filtered DataView in C#

I have a DataView which was filtered to contain only those records I need. On top of that I would like to get the first record in the Dataview.
//appDV contains a bunch of records with different LOAN_STATUS. Here I'm filtering it by Approved
appDV.RowFilter = "LOAN_STATUS = 'Approved'";
appDV.Sort = "CREATE_TIME DESC";
// If more than one record, take the 1st record
appuser = new AppUserVO();
appuser.APPUSER_ID = Convert.ToInt32(appDV.Table.Rows[0]["APPUSER_ID"].ToString());
appuser.BankLenderId = appDV.Table.Rows[0]["BANK_LENDERID"].ToString().Trim();
AppList.Add(appuser);
return AppList;
The code above is not returning the correct Row... because it is returning me the Row of the DataView BEFORE the filter was applied.
What am I doing wrong?
I don't think you need the .Table. call and instead should use
appDV.Rows[0]["APPUSER_ID"].ToString();
After you set sort expression and row filter, you have to call DataView.ToTable()
To get a column value from the first row :
string columnVal= appDV.ToTable().Rows[0]["COLUMN_NAME"].ToString();
You must use the .ToTable() first to convert you retrieved values in the DataView to a DataTable.

C# custom combobox sorting

Is it possible to have a custom sort/display order in a combox ? Say I want a special value "MasterValue" before all the others.
Instead of adding strings, create a class that implements IComparable and overrides ToString.
Add instances of that class to your ComboBox
The following code will do the trick.
Create a separate list of the items you want to sort and then use AddRange.
comboBox1.Items.Add("Master");
List<String> listToSort = new List<String>();
listToSort.Add("6nd");
listToSort.Add("3nd");
listToSort.Add("5nd");
listToSort.Add("4nd");
listToSort.Add("2nd");
listToSort.Sort();
comboBox1.Items.AddRange(listToSort.ToArray<String>());
Create a data source as a view (i.e. stored procedure) that returns an additional field valued 1.
Then get the data source, and add an additional row to the data view, with the additional field valued at 0.
Then sort the view, by that field initially, and then by the description of the field.
This will always then put your 'Master Value' first, then sort the others alphabetically.
private void PopulateCombo()
{
// get data view that returns 3 columns,
//master sort column set to 1, id, and description //
DataView view = GetSource();
// add a new row to the data source that has column values
// 0 for master sort column (all others are returned 1
// an appropriate ID and a description
// data view columns = master sort column, id, description
view.Table.Rows.Add(new object[] {0, 1, "MasterValue"});
// sort first by master column then description //
view.Sort = "MasterSortColumn ASC, Description ASC";
combo.DataSource = view;
combo.ValueMember = "Id";
combo.DisplayMember = "Description";
}

Categories

Resources