AdvancedDataGrid Column Sorting Question - sorting

I have am using an mx:advanceddatagrid and I running into a problem with grouped column sorting. A screenshot of what my grid looks like is here: http://i.stack.imgur.com/waAi7.png
I have the following kind of data:
PRODUCT_ID PROD_NAME CATEGORY TYPE SubType SubType_descr
1 p_1 c1_y t1
t1_s1 sub_1*
t1_s2 sub_2*
t1_s4 sub_4*
t1_s5 sub_5*
2 p_2 c1_x t1
t1_s1 sub_1
t1_s2 sub_2
t1_s3 sub_3
3 p_3 c1_x t1
t1_s1 sub_1
t1_s2 sub_2*
t1_s3 sub_3*
Now, the dataset is of the type arrayCollection. I manually move it into GroupingCollection2 when a setter fires the Binding Event;
protected function setGrouping(columnNames:Array):void{
_groupingColumns = [];
if (columnNames.length > 0) {
var _groupedData:GroupingCollection2 = new GroupingCollection2();
var _grouping:Grouping = new Grouping();
for (var i:int=0;i<columnNames.length;i++) {
var gc:GroupingField = new GroupingField(columnNames[i]);
_groupingColumns.push(gc);
}
_groupedData.source = _ds;
_grouping.fields = _groupingColumns;
_groupedData.grouping = _grouping
_groupedData.refresh();
_data = _groupedData;
} else {
_data = _ds;
}
setGridColumns();
}
Although I am grouping on Product_Id, i achieve the above look by a labelFunction as shown below:
col.labelFunction = function (item:Object,column:AdvancedDataGridColumn):String {
if (item.hasOwnProperty('GroupLabel') && item.GroupLabel != null) {
if (item.children.length > 0) {
return item.children[0][column.dataField];
}
else {
return "";
}
}
else {
return "";
}
}
The data I recieve from the server is of the kind shown below
PRODUCT_ID PROD_NAME CATEGORY TYPE SubType SubType_descr
-------------------------------------------------------------------
1 p_1 c1_y t1 t1_s1 sub_1*
2 p_2 c1_y t1 t1_s2 sub_2*
3 p_3 c1_y t1 t1_s3 sub_3*
-------------------------------------------------------------------
4 p_4 c1_x t1 t1_s1 sub_1*
5 p_5 c1_x t1 t1_s2 sub_2*
6 p_6 c1_x t1 t1_s3 sub_3*
In short I am taking all the common column values (Product, Category, Type) and putting them in the first row, all the changing values in the sub-rows (sub_type, subtype_descr)
I would like to sort this gird on Prod_Name, Category and type columns as well but sonething like the following is not working, even though the underlying data gets sorted.
public var _sort_direction:Boolean = false;
protected function adg1_headerReleaseHandler(event:AdvancedDataGridEvent):void
{
var sort:Sort = new Sort();
sort.fields = [new SortField(event.dataField, true, _sort_direction)];
_ds.sort = sort;
_ds.refresh();
if (DefaultGroupColumn != null && temp[0] != DefaultGroupColumn) {
temp.push(DefaultGroupColumn);
}
setGrouping(temp);
adg1.validateNow();
_sort_direction = !_sort_direction;
}
all help is really appreciated.

The answer to this was so simple, but Adobe documentation and some other blogs sent me on a wild goose chase...
for (var i:int=0;i<columnNames.length;i++) {
var gc:GroupingField = new GroupingField(columnNames[i]);
gc.compareFunction = positionCompareFunction;
gc.descending = sort_dir;
_groupingColumns.push(gc);
}
A colleague (thanks Samitt) helped me figure this out. Just add gc.descending and the grouping will sort on the grouped column.

Related

Comparing two lists with multiple conditions

I have two different lists of same type. I wanted to compare both lists and need to get the values which are not matched.
List of class:
public class pre
{
public int id {get; set;}
public datetime date {get; set;}
public int sID {get; set;}
}
Two lists :
List<pre> pre1 = new List<pre>();
List<pre> pre2 = new List<pre>();
Query which I wrote to get the unmatched values:
var preResult = pre1.where(p1 => !pre
.any(p2 => p2.id == p1.id && p2.date == p1.date && p2.sID == p1sID));
But the result is wrong here. I am getting all the values in pre1.
Here is solution :
class Program
{
static void Main(string[] args)
{
var pre1 = new List<pre>()
{
new pre {id = 1, date =DateTime.Now.Date, sID=1 },
new pre {id = 7, date = DateTime.Now.Date, sID = 2 },
new pre {id = 9, date = DateTime.Now.Date, sID = 3 },
new pre {id = 13, date = DateTime.Now.Date, sID = 4 },
// ... etc ...
};
var pre2 = new List<pre>()
{
new pre {id = 1, date =DateTime.Now.Date, sID=1 },
// ... etc ...
};
var preResult = pre1.Where(p1 => !pre2.Any(p2 => p2.id == p1.id && p2.date == p1.date && p2.sID == p1.sID)).ToList();
Console.ReadKey();
}
}
Note:Property date contain the date and the time part will be 00:00:00.
I fixed some typos and tested your code with sensible values, and your code would correctly select unmatched records. As prabhakaran S's answer mentions, perhaps your date values include time components that differ. You will need to check your data and decide how to proceed.
However, a better way to select unmatched records from one list compared against another would be to utilize a left join technique common to working with relational databases, which you can also do in Linq against in-memory collections. It will scale better as the sizes of your inputs grow.
var preResult = from p1 in pre1
join p2 in pre2
on new { p1.id, p1.date, p1.sID }
equals new { p2.id, p2.date, p2.sID } into grp
from item in grp.DefaultIfEmpty()
where item == null
select p1;

Dynamic LINQ Where query with joining other tables

I have several tables (the exact number is not known when the program is build) looking like this (the number of rows and columns may differ from table to table):
The source data is stored in a data set. Now I want to generate a new table where all data of all ids is stored (the picture shows only the result for id 10 and 20 but the target table should contain the data for all ids):
The equivalent SQLite statement for that looks like this:
SELECT * FROM Dataset
JOIN Datensatz2 ON (Dataset.ID=Datensatz2.ID)
JOIN Datensatz3 ON (Datensatz3.ID=Dataset.ID)
JOIN Datensatz4 ON (Datensatz4.ID=Dataset.ID)
WHERE Dataset.Id=10
UNION
SELECT * FROM Dataset
JOIN Datensatz2 ON (Dataset.ID=Datensatz2.ID)
JOIN Datensatz3 ON (Datensatz3.ID=Dataset.ID)
JOIN Datensatz4 ON (Datensatz4.ID=Dataset.ID)
WHERE Dataset.Id=20
...
The double id columns will be removed afterwards so donĀ“t worry about that. The questions is now how to convert it as a dynamic LINQ query?
There are plenty of open question but maybe this helps to solve it. Since the tables are already stored in a DataSet you could use Linq-To-DataSet and Enumerable.GroupBy to group by ID:
var idTables = ds.Tables.Cast<DataTable>().Where(t => t.Columns.Contains("Id"));
if(!idTables.Any()){ MessageBox.Show("No id-tables"); return; }
var idRowGroups = idTables.SelectMany(t => t.AsEnumerable())
.GroupBy(row => row.Field<int>("Id"))
.Select(grp => new { ID = grp.Key, Rows = grp });
foreach(var idGroup in idRowGroups)
{
Console.WriteLine("ID:{0} Rows:{1}"
, idGroup.ID
, String.Join(" | ", idGroup.Rows.Select(row => String.Join(",", row.ItemArray))));
}
Sample data:
var ds = new DataSet();
DataTable t1 = new DataTable();
t1.Columns.Add("Id", typeof(int));
t1.Columns.Add("Data", typeof(int));
t1.Rows.Add(1, 1);
t1.Rows.Add(2, 10);
t1.Rows.Add(3, 100);
t1.Rows.Add(4, 1000);
ds.Tables.Add(t1);
t1 = new DataTable();
t1.Columns.Add("Id", typeof(int));
t1.Columns.Add("Data", typeof(int));
t1.Rows.Add(4, 5);
t1.Rows.Add(5, 50);
t1.Rows.Add(7, 500);
t1.Rows.Add(3, 5997);
ds.Tables.Add(t1);
t1 = new DataTable();
t1.Columns.Add("Id", typeof(int));
t1.Columns.Add("Data1", typeof(int));
t1.Columns.Add("Data2", typeof(int));
t1.Rows.Add(1, 5, 0);
t1.Rows.Add(3, 7, 1);
t1.Rows.Add(5, 9, 11);
t1.Rows.Add(7, 11, 222);
ds.Tables.Add(t1);
Output:
ID:1 Rows:1,1 | 1,5,0
ID:2 Rows:2,10
ID:3 Rows:3,100 | 3,5997 | 3,7,1
ID:4 Rows:4,1000 | 4,5
ID:5 Rows:5,50 | 5,9,11
ID:7 Rows:7,500 | 7,11,222
Ok, I finally made it but it seems to be much too complicated. If someone is able to help me improve the solution he is very welcome.
DataSet dsResult = new DataSet();
var idTables = ds.Tables.Cast<DataTable>().Where(t => t.Columns.Contains("ID"));
if (!idTables.Any()) { MessageBox.Show("No id-tables"); return; }
var idRowGroups = idTables.SelectMany(t => t.AsEnumerable())
.GroupBy(row => row.Field<Int64>("ID"))
.Select(grp => new { ID = grp.Key, Rows = grp });
foreach (var idGroup in idRowGroups)
{
var liste = idGroup.Rows.ToList();
for (int i = 0; i < liste.Count; i++)
{
if (!dsResult.Tables.Contains(liste[i].Table.TableName))
{
dsResult.Tables.Add(liste[i].Table.TableName);
foreach (DataColumn dtCol in liste[i].Table.Columns)
{
if (dsResult.Tables[liste[i].Table.TableName].Columns.Contains("ID"))
dsResult.Tables[liste[i].Table.TableName].Columns.Add(dtCol.ColumnName+i.ToString());
else
{
dsResult.Tables[liste[i].Table.TableName].Columns.Add(dtCol.ColumnName);
}
dsResult.Tables[liste[i].Table.TableName].Columns[dtCol.ColumnName].DataType = dtCol.DataType;
}
}
DataRow dRow = dsResult.Tables[liste[i].Table.TableName].NewRow();
dRow.ItemArray = liste[i].ItemArray;
dsResult.Tables[liste[i].Table.TableName].Rows.Add(dRow);
}
IEnumerable<IEnumerable<DataRow>> allTablesRows = dsResult.Tables.Cast<DataTable>()
.Select(table => table.AsEnumerable())
.CartesianProduct();
int k = 0;
foreach (var rows in allTablesRows)
{
DataRow zRow = dsErgebnis.Tables[2].NewRow();
foreach (DataRow dRow in rows)
{
for (int i = 0; i < dRow.ItemArray.Length; i++)
{
zRow[k] = dRow.ItemArray[i];
k++;
}
}
k = 0;
dsErgebnis.Tables[2].Rows.Add(zRow);
}
dsResult.Clear();
}
First I filter the content by ID.
Then I put the result in a new tables (all rows with the ID 10 I found in 'Datasatz2' in dataset 'ds' for example I put to a new table 'Datasatz2' in the dataset 'dsResult').
At least I build the cartesian product of all tables and store it in dtaset dsErgebnis.
The result is what I expect but as mentioned before I am not satisfied with the solution.

Dynamic PIVOT using C# Linq

I am trying to use following code to create the PIVOT but its not working.
It's giving me compile time error. I don't know linq so unable to use it.
Please help :
DataTable Pivot(DataTable dt, DataColumn pivotColumn, DataColumn pivotValue) {
// find primary key columns
//(i.e. everything but pivot column and pivot value)
DataTable temp = dt.Copy();
temp.Columns.Remove( pivotColumn.ColumnName );
temp.Columns.Remove( pivotValue.ColumnName );
string[] pkColumnNames = temp.Columns.Cast(<DataColumn>)
.Select( c => c.ColumnName )
.ToArray();
// prep results table
DataTable result = temp.DefaultView.ToTable(true, pkColumnNames).Copy();
result.PrimaryKey = result.Columns.Cast(<DataColumn>).ToArray();
dt.AsEnumerable()
.Select(r =>; r[pivotColumn.ColumnName].ToString())
.Distinct().ToList()
.ForEach (c => result.Columns.Add(c, pivotColumn.DataType));
// load it
foreach( DataRow row in dt.Rows ) {
// find row to update
DataRow aggRow = result.Rows.Find(
pkColumnNames
.Select( c => row[c] )
.ToArray() );
// the aggregate used here is LATEST
// adjust the next line if you want (SUM, MAX, etc...)
aggRow[row[pivotColumn.ColumnName].ToString()] = row[pivotValue.ColumnName];
}
return result;
}
Code from : http://michaeljswart.com/2011/06/forget-about-pivot/
Moreover it tried to use following code, it works well except for it is not giving total sum for Value Column
public DataTable GetInversedDataTable(DataTable table, string columnX, string columnY, string columnZ, string nullValue, bool sumValues)
{
//Create a DataTable to Return
DataTable returnTable = new DataTable();
DataTable tempTable = table.Clone();
if (string.IsNullOrEmpty(columnX))
{
columnX = table.Columns[0].ColumnName;
}
tempTable.Columns.Remove(columnX);
//Add a Column at the beginning of the table
//returnTable.Columns.Add(columnY);
returnTable = tempTable.Clone();
//Read all DISTINCT values from columnX Column in the provided DataTale
List<string> columnXValues = new List<string>();
foreach (DataRow dr in table.Rows)
{
string columnXTemp = dr[columnX].ToString();
if (!columnXValues.Contains(columnXTemp))
{
//Read each row value, if it's different from others provided, add to the list of values and creates a new Column with its value.
columnXValues.Add(columnXTemp);
returnTable.Columns.Add(columnXTemp);
}
}
//Verify if Y and Z Axis columns re provided
if (!string.IsNullOrEmpty(columnY) && !string.IsNullOrEmpty(columnZ))
{
//Read DISTINCT Values for Y Axis Column
List<string> columnYValues = new List<string>();
foreach (DataRow dr in table.Rows)
{
if (!columnYValues.Contains(dr[columnY].ToString()))
{
columnYValues.Add(dr[columnY].ToString());
}
}
//Loop all Column Y Distinct Value
foreach (string columnYValue in columnYValues)
{
//Creates a new Row
DataRow drReturn = returnTable.NewRow();
drReturn[0] = columnYValue;
//foreach column Y value, The rows are selected distincted
DataRow[] rows = table.Select((columnY + "='") + columnYValue + "'");
//Read each row to fill the DataTable
foreach (DataRow dr in rows)
{
string rowColumnTitle = dr[columnX].ToString();
//Read each column to fill the DataTable
foreach (DataColumn dc in returnTable.Columns)
{
if (dc.ColumnName == rowColumnTitle)
{
//If Sum of Values is True it try to perform a Sum
//If sum is not possible due to value types, the value displayed is the last one read
if (sumValues)
{
try
{
drReturn[rowColumnTitle] = Convert.ToDecimal(drReturn[rowColumnTitle]) + Convert.ToDecimal(dr[columnZ]);
}
catch
{
drReturn[rowColumnTitle] = dr[columnZ];
}
}
else
{
drReturn[rowColumnTitle] = dr[columnZ];
}
}
}
}
returnTable.Rows.Add(drReturn);
}
}
else
{
throw new Exception("The columns to perform inversion are not provided");
}
//if a nullValue is provided, fill the datable with it
if (!string.IsNullOrEmpty(nullValue))
{
foreach (DataRow dr in returnTable.Rows)
{
foreach (DataColumn dc in returnTable.Columns)
{
if (string.IsNullOrEmpty(dr[dc.ColumnName].ToString()))
{
dr[dc.ColumnName] = nullValue;
}
}
}
}
return returnTable;
}
GetInversedDataTable(dtNormal, "Dated", "OrderStatus", "Qty", " ", true);
Please help :)
Here is the code with the compilation errors corrected:
DataTable Pivot(DataTable dt, DataColumn pivotColumn, DataColumn pivotValue) {
// find primary key columns
//(i.e. everything but pivot column and pivot value)
DataTable temp = dt.Copy();
temp.Columns.Remove( pivotColumn.ColumnName );
temp.Columns.Remove( pivotValue.ColumnName );
string[] pkColumnNames = temp.Columns.Cast<DataColumn>()
.Select( c => c.ColumnName )
.ToArray();
// prep results table
DataTable result = temp.DefaultView.ToTable(true, pkColumnNames).Copy();
result.PrimaryKey = result.Columns.Cast<DataColumn>().ToArray();
dt.AsEnumerable()
.Select(r => r[pivotColumn.ColumnName].ToString())
.Distinct().ToList()
.ForEach (c => result.Columns.Add(c, pivotColumn.DataType));
// load it
foreach( DataRow row in dt.Rows ) {
// find row to update
DataRow aggRow = result.Rows.Find(
pkColumnNames
.Select( c => row[c] )
.ToArray() );
// the aggregate used here is LATEST
// adjust the next line if you want (SUM, MAX, etc...)
aggRow[row[pivotColumn.ColumnName].ToString()] = row[pivotValue.ColumnName];
}
return result;
}
I changed Cast(<DataColumn>) to Cast<DataColumn>() in two locations and got rid of the semicolon in the middle of a lambda expression. The second part of your question is a little trickier. You may want to ask it as its own question.
Good one., but you might want to replace the below line
.ForEach (c => result.Columns.Add(c, pivotColumn.DataType));
with this (change pivotColumn to pivotValue)
.ForEach (c => result.Columns.Add(c, pivotValue.DataType));
Works perfectly for my requirement.

EF single entity problem

I need to return a single instance of my viewmodel class from my repository in order to feed this into a strongly-typed view
In my repository, this works fine for a collection of viewmodel instances:
IEnumerable<PAWeb.Domain.Entities.Section> ISectionsRepository.GetSectionsByArea(int AreaId)
{
var _sections = from s in DataContext.Sections where s.AreaId == AreaId orderby s.Ordinal ascending select s;
return _sections.Select(x => new PAWeb.Domain.Entities.Section()
{
SectionId = x.SectionId,
Title = x.Title,
UrlTitle = x.UrlTitle,
NavTitle = x.NavTitle,
AreaId = x.AreaId,
Ordinal = x.Ordinal
}
);
}
But when I attempt to obtain a single entity, like this:
public PAWeb.Domain.Entities.Section GetSection(int SectionId)
{
var _section = from s in DataContext.Sections where s.SectionId == SectionId select s;
return _section.Select(x => new PAWeb.Domain.Entities.Section()
{
SectionId = x.SectionId,
Title = x.Title,
UrlTitle = x.UrlTitle,
NavTitle = x.NavTitle,
AreaId = x.AreaId,
Ordinal = x.Ordinal
}
);
}
I get
Error 1 Cannot implicitly convert type
'System.Linq.IQueryable<PAWeb.Domain.Entities.Section>' to
'PAWeb.Domain.Entities.Section'. An explicit conversion exists
(are you missing a cast?)"
This has got to be simple, but I'm new to c#, and I can't figure out the casting. I tried (PAWeb.Domain.Entities.Section) in various places, but no success. Can anyone help??
Your query is returning an IQueryable, which could have several items. For example, think of the difference between an Array or List of objects and a single object. It doesn't know how to convert the List to a single object, which one should it take? The first? The last?
You need to tell it specifically to only take one item.
e.g.
public PAWeb.Domain.Entities.Section GetSection(int SectionId)
{
var _section = from s in DataContext.Sections where s.SectionId == SectionId select s;
return _section.Select(x => new PAWeb.Domain.Entities.Section()
{
SectionId = x.SectionId,
Title = x.Title,
UrlTitle = x.UrlTitle,
NavTitle = x.NavTitle,
AreaId = x.AreaId,
Ordinal = x.Ordinal
}
).FirstOrDefault();
}
This will either return the first item, or null if there are no items that match your query. In your case that won't happen unless the table is empty since you don't have a where clause.

How to select same column's name from different table in Linq?

I've 2 tables with same column's name, for example, both table A and table B has column's name "Test". I want to select column Test from both table A and B to entity class. How can I do this?
It sounds like you want the two entities of TableA and TableB merged into a new object. You can use the .Select() extension method to create a new anonymous type, or into a class that you already have defined.
The requirement here is that you've got to find a common attribute between TableA and TableB. Here I assume you've got something like ID to match them together.
Anonymous Type
var mergedTests = from a in db.TableA
join b in db.TableB on a.CommonID equals b.CommonID
select new
{ TestFromA = a.Test, TestFromB = b.Test }
.ToList();
Existing Class
List<MyCustomTests> mergedTests = from a in db.TableA
join b in db.TableB on a.CommonID equals b.CommonID
select new MyCustomTests
{ TestName= a.Test, ShortName= b.Test }
.ToList();
class Program
{
static void Main(string[] args)
{
var A = new Data[] {
new Data { Test = 1, Relation = 1 },
new Data { Test = 2, Relation = 2 },
new Data { Test = 3, Relation = 3 },
new Data { Test = 4, Relation = 4 },
new Data { Test = 5, Relation = 5 },
};
var B = new Data[] {
new Data { Test = 2, Relation = 2 },
new Data { Test = 3, Relation = 3 },
new Data { Test = 5, Relation = 5 },
};
var res = from a in A
join b in B on a.Relation equals b.Relation
select new { TestA = a.Test, TestB = b.Test };
}
}
class Data
{
public int Test;
public int Relation;
}

Resources