Number of records in grid AX 2012 - axapta

I tried to count num of rows in grid in runtime with this code
FormRun caller;
FormDataSource fds;
QueryRun queryRun;
int64 rows;
fds = caller.dataSource();
query = fds.query();
queryRun = new QueryRun(query);
rows = SysQuery::countTotal(queryRun); //this returns -1587322268
rows = SysQuery::countLoops(queryRun); //this returs 54057
The last line of code is closest to what i need because there are 54057 lines but if i add filters it still returns 54057.
I want logic to get the number rows that grid has in the moment of calling the method.

Your query has more than one datasource.
The best way to explain your observation is to look at the implementation of countTotal and countLoops.
public client server static Integer countTotal(QueryRun _queryRun)
{
container c = SysQuery::countPrim(_queryRun.pack(false));
return conpeek(c,1);
}
public client server static Integer countLoops(QueryRun _queryRun)
{
container c = SysQuery::countPrim(_queryRun.pack(false));
return conpeek(c,2);
}
private server static container countPrim(container _queryPack)
{
...
if (countQuery.dataSourceCount() == 1)
qbds.addSelectionField(fieldnum(Common,RecId),SelectionField::Count);
countQueryRun = new QueryRun(countQuery);
while (countQueryRun.next())
{
common = countQueryRun.get(countQuery.dataSourceNo(1).table());
counter += common.RecId;
loops++;
}
return [counter,loops];
}
If your datasource contains one datasource it adds count(RecId).
countTotal returns the number of records.
countLoops returns 1.
Pretty fast, as fast as the SQL allows.
If your datasource contains more than one datasource it does not add count(RecId).
countTotal returns the sum of recIds (makes no sense).
countLoops returns the number of records.
Also countLoops is slow if there are many records as they are counted one by one.
If you have two datasources and want a fast count, you are on your own:
fds = caller.dataSource();
queryRun = new QueryRun(fds.queryRun().query());
queryRun.query().dataSourceNo(2).joinMode(JoinMode::ExistsJoin);
queryRun.query().dataSourceNo(1).clearFields();
queryRun.query().dataSourceNo(1).addSelectionField(fieldnum(Common,RecId),SelectionField::Count);
queryRun.next();
rows = queryRun.getNo(1).RecId;
The reason your count did not respect the filters was because you used datasource.query() rather than datasource.queryRun().query(). The former is the static query, the latter is the dynamic query with user filters included.
Update, found some old code with a more general approach:
static int tableCount(QueryRun _qr)
{
QueryRun qr;
Query q = new Query(_qr.query());
int dsN = _qr.query().dataSourceCount();
int ds;
for (ds = 2; ds <= dsN; ++ds)
{
if (q.dataSourceNo(ds).joinMode() == JoinMode::OuterJoin)
q.dataSourceNo(ds).enabled(false);
else if (q.dataSourceNo(ds).joinMode() == JoinMode::InnerJoin)
{
q.dataSourceNo(ds).joinMode(JoinMode::ExistsJoin);
q.dataSourceNo(ds).fields().clearFieldList();
}
}
q.dataSourceNo(1).fields().clearFieldList();
q.dataSourceNo(1).addSelectionField(fieldNum(Common,RecId), SelectionField::Count);
qr = new QueryRun(q);
qr.next();
return any2int(qr.getNo(1).RecId);
}

Related

Sorting Gridview with Entity Framework Not Working as Intended

I have a gridview that i want to sort. I wrote the following method for it:
private void SortGridView(string sortExpression, string direction)
{
var constr = new AdminRequirementEF();
string sort = string.Concat("it.", sortExpression, " ", direction);
int pageSize = Convert.ToInt32(ddPageSize.SelectedItem.Text);
var results = constr.Projects;
int totalRecords = results.Count();
this.PopulatePager(totalRecords, pageIndex);
var sortedResults = constr.Projects.OrderBy(sort).Skip((pageIndex - 1) * pageSize).Take(pageNum).ToList();
grdMain.DataSource = sortedResults;
grdMain.DataBind();
}
The problem is sorting is applied on totalrecords not on per page filtered records. I want to use OrderBy(sort) after applying skip and take but it gives me an error stating skip can not be applied before orderby clause. Any help will be much appreciated.
You can get the constr.Projects collection sorted on its primary key
var results = constr.Projects.OrderBy(p => p.ProjectId)
and then apply the skip and take on the 'results' collection with sorting.
results = results.Skip((pageIndex - 1) * pageSize).Take(pageNum).OrderBy(sort).ToList();
This way you will get the records for particular page sorted as required.

Extracting max value in GridView column in a Web Performance Test

This pertains to .NET Web Performance Tests.
If I have an ASP.NET page with a GridView that has a column of ints, how do I write an extraction rule to get the largest int in the column?
I tried creating a custom extraction rule by inheriting from ExtractionRule and in the Extract method using e.Response.HtmlDocument.GetFilteredHtmlTags however, the HtmlTags returned don't seem to expose their innerHtml contents.
Perhaps you can write an extraction rule that gets the whole column, then process the numbers to get their maximum value. Alternatively, use a built-in extraction rule to get the whole column, then write a plugin to get the maximum value. In either case your code should expect a mixture of numbers and other text.
Ben Day has a great blog post containing two types that express similar concerns. TableColumnValueValidator and ExtractRandomValueFromTable.
http://www.benday.com/2013/08/19/validation-extraction-rules-for-visual-studio-2012-web-performance-tests/
In the Extract(object, ExtractionEventArgs), you need to parse the ExtractionEventArgs.Response.BodyString. Ben uses the HtmlAgilityPack library for this. http://www.nuget.org/packages/htmlagilitypack
Something like this is roughly the code you'd need. This is simliar logic to ExtractRandomValueFromTable.
This does not account for thead/tbody or cells that span multiple columns/rows.
HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(e.Response.BodyString);
HtmlNode table = doc.GetElementbyId(TableId); // TableId is a test property
HtmlNodeCollection columns = table.SelectNodes("//th");
int columnIndex = FindColumnIndexByName(columns, ColumnName); // ColumnName is a test property
HtmlNodeCollection rows = table.SelectNodes("//tr")
int maxValue = Int32.MinValue;
foreach(HtmlNode row in rows)
{
HtmlNodeCollection cells = row.SelectNodes("./td");
// Todo check for bounds of cells here
HtmlNode cell = cells[columnIndex];
int value = Int32.MinValue;
Int32.TryParse(cell.InnerText.Trim(), out value);
maxValue = Math.Max(value, maxValue);
}
e.WebTest.Context.Add(ContextParameterName, maxValue);
int FindColumnIndexByName(HtmlNodeCollection columns, string columnName)
{
for(int i=0; i<columns.Count; i++)
if (String.Equals(columns[i].InnerText, columnName, StringComparison.OrdinalIgnoreCase))
{
return i;
}
return -1;
}

Faster database access by index

I have this code
using (var contents = connection.CreateCommand())
{
contents.CommandText = "SELECT [subject],[note] FROM tasks";
var r = contents.ExecuteReader();
int zaehler = 0;
int zielzahl = 5;
while (r.Read())
{
if (zaehler == zielzahl)
{
//access r["subject"].ToString()
}
zaehler++;
}
}
I want to make it faster by accessing zielzahl directly like r[zielzahl] instead of iterating through all entries. But
r[zielzahl]["subject"]
does not work aswell as
r["subject"][zielzahl]
How do I access the column subject of result number zielzahl?
To get only the sixth record, use the OFFSET clause:
SELECT subject, note
FROM tasks
LIMIT 1 OFFSET 5
Please note that the order of returned records is not guaranteed unless you use the ORDER BY clause.

how to get unique records from data table randomly using c#?

hiee every one, i am developing a small application from where all questions are coming randomly.
i have use the default random method to get random data but it gives duplicate rows twice. so what i need is to get distinct rows into data table.
i am using following method to get rendom records...
Random rDom = new Random();
dtRandom = dt.Clone();
int rw = 0;
for (int ctr = 1; ctr <= dt.Rows.Count; ctr++)
{
rw = rDom.Next(1, dt.Rows.Count);
dtRandom.ImportRow(dt.Rows[rw]);
}
dtRandom.AcceptChanges();
so, how can i achieve distinct records from datatable ?
As you are aware, random number generation may generate the same number multiple times. Either check for the existence of the imported row before importing it into your datatable, if there is a unique surrogate key / primary key. Otherwise you can use this approach to get the distinct values from the final DataTable:
DataTable distinctTable = new DataView(dtRandom).ToTable(
true, new string[] { "column1", "column2", "etc." });
From http://msdn.microsoft.com/en-us/library/wec2b2e6.aspx
You need to keep the same Random object.
Put it outside your static method as a static member
private static Random rand = new Random();
public static int rInt(int exclUB, int incLB = 0)
{
int t = rand.Next(incLB, exclUB);
return t;
}
Detail
Random Number Generation - Same Number returned

Retrieve Cellset Value in SSAS\MDX

Im writing SSAS MDX queries involving more than 2 axis' to retrieve a value. Using ADOMD.NET, I can get the returned cellset and determine the value by using
lblTotalGrossSales.Text = CellSet.Cells(0).Value
Is there a way I can get the CellSet's Cell(0) Value in my MDX query, instead of relying on the data returning to ADOMD.NET?
thanks!
Edit 1: - Based on Daryl's comment, here's some elaboration on what Im doing. My current query is using several axis', which is:
SELECT {[Term Date].[Date Calcs].[MTD]} ON 0,
{[Sale Date].[YQMD].[DAY].&[20121115]} ON 1,
{[Customer].[ID].[All].[A612Q4-35]} ON 2,
{[Measures].[Loss]} ON 3
FROM OUR_CUBE
If I run that query in Management Studio, I am told Results cannot be displayed for cellsets with more than two axes - which makes sense since.. you know.. there's more than 2 axes. However, if I use ADOMD.NET to run this query in-line, and read the returning value into an ADOMD.NET cellset, I can check the value at cell "0", giving me my value... which as I understand it (im a total noob at cubes) is the value sitting where all these values intersect.
So to answer your question Daryl, what I'd love to have is the ability to have the value here returned to me, not have to read in a cell set into the calling application. Why you may ask? Well.. ultimately I'd love to have one query that performs several multi-axis queries to return the values. Again.. Im VERY new to cubes and MDX, so it's possible Im going at this all wrong (Im a .NET developer by trade).
Simplify your query to return two axis;
SELECT {[Measures].[Loss]} ON 0, {[Term Date].[Date Calcs].[MTD] * [Sale Date].[YQMD].[DAY].&[20121115] * [Customer].[ID].[All].[A612Q4-35]} ON 1 FROM OUR_CUBE
and then try the following to access the cellset;
string connectionString = "Data Source=localhost;Catalog=AdventureWorksDW2012";
//Create a new string builder to store the results
System.Text.StringBuilder result = new System.Text.StringBuilder();
AdomdConnection conn = new AdomdConnection(connectionString);
//Connect to the local serverusing (AdomdConnection conn = new AdomdConnection("Data Source=localhost;"))
{
conn.Open();
//Create a command, using this connection
AdomdCommand cmd = conn.CreateCommand();
cmd.CommandText = #"SELECT { [Measures].[Unit Price] } ON COLUMNS , {[Product].[Color].[Color].MEMBERS-[Product].[Color].[]} * [Product].[Model Name].[Model Name]ON ROWS FROM [Adventure Works] ;";
//Execute the query, returning a cellset
CellSet cs = cmd.ExecuteCellSet();
//Output the column captions from the first axis//Note that this procedure assumes a single member exists per column.
result.Append("\t\t\t");
TupleCollection tuplesOnColumns = cs.Axes[0].Set.Tuples;
foreach (Microsoft.AnalysisServices.AdomdClient.Tuple column in tuplesOnColumns)
{
result.Append(column.Members[0].Caption + "\t");
}
result.AppendLine();
//Output the row captions from the second axis and cell data//Note that this procedure assumes a two-dimensional cellset
TupleCollection tuplesOnRows = cs.Axes[1].Set.Tuples;
for (int row = 0; row < tuplesOnRows.Count; row++)
{
for (int members = 0; members < tuplesOnRows[row].Members.Count; members++ )
{
result.Append(tuplesOnRows[row].Members[members].Caption + "\t");
}
for (int col = 0; col < tuplesOnColumns.Count; col++)
{
result.Append(cs.Cells[col, row].FormattedValue + "\t");
}
result.AppendLine();
}
conn.Close();
TextBox1.Text = result.ToString();
} // using connection
Source : Retrieving Data Using the CellSet
This is fine upto select on columns and on Rows. It will be helpful analyze how to traverse sub select queries from main query.

Resources