How to retrieve data with offset and limit using webservice request? - axapta

I am trying to build an AX service to retrieve data from InventTable in Microsoft Dynamics AX 2009.
With reference to https://community.dynamics.com/ax/f/33/t/70476.aspx ,I tried to execute a code in AOT Job for retrieving data with modifieddate="2/7/2013"
The code sample is as below:
static void SelectQueryTest(Args _args)
{
Query q = new Query();
QueryRun qr;
QueryBuildDataSource qbds;
int64 countItem;
InventTable inventTable;
Fromdate FromDate = 2\7\2013;
;
qbds = q.addDataSource(tableNum(InventTable));
qbds.addRange(fieldNum(InventTable, modifiedDateTime)).value(date2StrUsr(FromDate ));
qr = new QueryRun(q);
countItem =SysQuery::countTotal(qr);
if(countItem>0)
{
while(qr.next())
{
inventTable = qr.get(tableNum(inventTable));
info(strfmt("Item Name: %1", inventTable.ItemName));
}
}
else
{
info("No records found");
}
}
Can any one suggest me how to write a code which retrieves data using offset and limit that is taken from a webservice request.

limit and offset are not available in x++ when querying AX.
In my opinion you have 2 options to acheive the same goal.
Order your result set by recId, store the recId, and the use where recId > yourRecId for your offset. You would also need to count the records manually using something like while select.
Use x++ to query the SQL database directly, in which case you should be able to use any SQL supported by the server

You will most likely do not need to make a service yourself, as there are standard ways to do it.
Take a look on the answers here: Fetching data from dynamics ax 2009 using Ax webservices and C#
Also take a look on this screencast.

Related

How to filter by date and do a Form's query by code?

I have to do a Form query by code. The datasource table is CustomVendTable(is a custom table).
I open a form and in my init method I get the table caller :
public void init ()
{
VendTable = myVendTableCaller;
myVendTableCaller = element.args().record();
// There is a dialog and get a date by a _Dialog_ and save in a date variable
super();
}
In my data source I have a build a query. The table in my datasource is related whit VendTable. I filter by code my DataSource by myVendTableCaller.RecId and variable date dateByDialog inserted in the opening dialog
My query is this:
public void executeQuery()
{
query q = new Query();
QueryBuildRange qbr;
QueryBuildDataSource qbds ;
QueryRun queryRun;
qbds = q.addDataSource(tableNum(CustomVendTable) );
qbds.addRange(fieldNum(CustomVendTable, ValidFrom)).value(SysQuery::value( strFmt ("<=%1 ", _dateByDialog)) ) ;
qbds.addRange(fieldNum(CustomVendTable, ValidTo)).value(SysQuery::value( strFmt (">=%1 ", _dateByDialog))) ;
qbds.addRange(fieldNum(CustomVendTable, Vendor )).value(SysQuery::value(myVendTableCaller.recId));
queryRun = new QueryRun (q);
CustomVendTable_ds.query(queryRun.query());
super();
}
*For information there is a Table Relation CustomVendTable.Vendor == VendTable.RecId
So, I have some problems! I think not to be able to make a correct query by date. The fields ValidFrom - ValidTo are UTCdatetime type.
1) I have to convert my _dateByDialog in UTC ? How to do ? It' s correct my query date way ?
Considering that the conversion is not impossible, my BIG problem is that by filtering by date, if I have only one record with recid same range and dates I can somehow see it, BUT if there are more record with these same characteristics (If I have 2 record) I don't see nothing! My Form Grid is void!
I have read that you should set the Session date time (I'm talking about this ) to have control over dates.
I still believe that I do not build my Query very well.
Do you have an idea how can I do ?
If you used DateTimeUtil::newDateTime and made new UTCDateTime parameters for the dates?
https://community.dynamics.com/ax/b/alirazatechblog/archive/2012/09/03/date-to-utcdatetime-convertion-dynamics-ax-2012
Maybe you use a table which use date effective. You assume you have to do the selection yourself, this is not true.
Instead call method validTimeStateAsOfDate on the datasource. See this answer for details.

Entity Framework Update Time & Date Column with Parameterized

I have changed all my code from the raw ADO.NET SQLCommand to Entity Framework in order to have easier accessibility of changing my code in the future. However, I have realized there are many drawbacks in Entity Framework it is not as simple as injecting raw SQL commands into the database. Moreover, I have used Reverse Engineering to generate the Models & Mapping for MS Sql Server.
Currently, I am trying to do the following but none of the columns are getting updated.
string sql = #"UPDATE [ProductDB] SET CreatedProduct_Time=getdate(), CreatedProduct_Date=getdate()" + " WHERE [Material_No] = #Material_No";
db.Database.ExecuteSqlCommand(sql, new SqlParameter("#Material_No", materialnotxt));
The columns are not getting updated.
I am having a doubt whether Entity Framework will help me maintain my code for future use and is it worth the headache using it instead of the old raw SQL code? So far there are many constraints and it requires a higher learning curve.
Some confusing parts I have find online what is the difference between the context.Database.ExecuteSqlCommand and this MSDN http://msdn.microsoft.com/en-us/library/bb738684.aspx the code looks entirely different then my approach.
EDIT
I have used a different approach to insert the Date and Time while inserting all the info from the textbox.
using (var db = new ROGContext())
{
ProductDB product = new ProductDB
{
Material_No = long.Parse(MaterialNo_txtbox.Text),
Product_Line = ProductLineDropDownList1.SelectedItem.Text,
Product_Description = Description_txtbox.Text,
Size = Size_txtbox.Text,
UOM = UOM_txtbox.Text,
SupplierID = long.Parse(SupplierCountryListBox.SelectedItem.Value),
CreatedProduct_Date = DateTime.Parse(System.DateTime.Now.ToShortDateString()), //in the SQL database I have set the datatype as date to get yyyy/mm/dd
CreatedProduct_Time = DateTime.Now.TimeOfDay //in the SQL database I have set the datatype as time(0) to get hh:mm:ss
};
long queryselect = (from materialno in db.ProductDBs
where materialno.Material_No == product.Material_No
select materialno.Material_No).SingleOrDefault();
if (queryselect != long.Parse(materialnotxt))
{
Label1.Text = "Product successfully added in database";
Label1.Visible = true;
db.ProductDBs.Add(product);
db.SaveChanges();
}
You can use Context.ExecuteStoreCommand for Insert, Update and Delete.
See in Page 64 of Entity Framework 4.0 Recipes: A Problem-Solution Approach
Answer your edited part:
ExecuteStoreQuery for Select
ExecuteStoreCommand for Insert, Update and Delete
Entity Framework v4 – Tips and Tricks

Query to fetch table names from AX takes too long

I am using the following code in X++ to get table names:
client server public static container tableNames()
{
tableId tableId;
int tablecounter;
Dictionary dict = new Dictionary();
container tableNamesList;
for (tablecounter=1; tablecounter<=dict.tableCnt(); tablecounter++)
{
tableId = dict.tableCnt2Id(tablecounter);
tableNamesList = conIns(tableNamesList,1,dict.tableName(tableId));
}
return tableNamesList;
}
Business connector code :
tablesList = (AxaptaContainer)Global.ax.
CallStaticClassMethod("Code_Generator", "tableNames");
for (int i = 1; i <= tablesList.Count; i++)
{
tableName = tablesList.get_Item(i).ToString();
tables.Add(tableName);
}
The application hangs for 2 - 3 minutes while fetching data. What could be the cause? Any optimizations?
Rather than use ConIns, use +=, it will be faster
tableNamesList += dict.tableName(tableId);
ConIns has to work out where in the container to place the insert. += just adds it to the end
As mentioned before avoid conIns() when appending elements to a container because it makes a new copy of the container. Use += instead to append in place.
Also, you may want to check for permissions and leave out temporary tables, table maps, and other special cases. Standard Ax has a method to build a table name lookup form that takes these things into account. Check the method Global::pickTable() for details.
You could avoid some calls through the business connector as well and build the entire list in Ax in a similar way and return that in a single function call.
If you are using Dynamics Ax 2012, you could skip the treeNode stuff and use the SysModelElement table to fetch the data and return it immediately as a .Net Array to easy up things on the other side.
public static System.Collections.ArrayList FetchTableNames_ModelElementTables()
{
SysModelElement element;
SysModelElementType elementType;
System.Collections.ArrayList tableNames = new System.Collections.ArrayList();
;
// The SysModelElementType table contains the element types
// and we need the recId for the next selection
select firstonly RecId
from elementType
where elementType.Name == 'Table';
// With the recId of the table element type,
// select all of the elements with that type (hence, select all of the tables)
while select Name
from element
where element.ElementType == elementType.RecId
{
tableNames.Add(element.Name);
}
return tableNames;
}
}
Alright, I have tried a lot of things and in the end, I decided to create a table consisting of all table names. This table will have a Job populating it. I am fetching records from this table.

MS CRM Dynamics in latest bound - how to discover all entities?

I am building a connector to CRM Dynamics.
I would like to get (discover) all the entities with their fields.
There for, I am using the IOrganizationService interface with RetrieveAllEntitiesRequest.
I do get all the entities names BUT I don't know how to get all fields (columns) of any entity.
please help...
hagai
It sounds like your almost there. This it taken from the MSDN sample: Dump Attribute Metadata to a File.
RetrieveAllEntitiesRequest request = new RetrieveAllEntitiesRequest()
{
EntityFilters = EntityFilters.Attributes,
RetrieveAsIfPublished = true
};
// Retrieve the MetaData.
RetrieveAllEntitiesResponse response = (RetrieveAllEntitiesResponse)_serviceProxy.Execute(request);
foreach (EntityMetadata currentEntity in response.EntityMetadata)
{
foreach (AttributeMetadata currentAttribute in currentEntity.Attributes)
{
Console.WriteLine("LogicalName: " + currentAttribute.LogicalName);
}
}
We need to create RetrieveAllEntitiesRequest first
RetrieveAllEntitiesRequest entityRequest = new RetrieveAllEntitiesRequest();
Then call the service.execute() to retrieve results
there is a blog post which explains really well.

Server Error due to paging issue

I think I sorted out my GridView1_PageIndexChanged event and thinking it should work
protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
GridView1.DataSourceID = "lqPackWeights";
GridView1.PageIndex = e.NewPageIndex;
}
However, when I now attempt to access page 2 of x, I receive the following:
Server Error in '/project' application.
This provider supports Skip() only over ordered queries returning entities or projections that contain all identity columns, where the query is a single-table (non-join) query, or is a Distinct, Except, Intersect, or Union (not Concat) operation.
I'm a bit confused by this, I'm not using skip as far as I can see unless I am going blind?
I am currently using SQL2000, is this a problem directly related to this instance of SQL?
Are you using LINQ to SQL? The problem seems unique to SQL Server 2000. See these MSDN articles on Troubleshooting (LINQ to SQL) and Standard Query Operator Translation (LINQ to SQL) for more information.
EDIT
A similiar question has been asked before, see: LINQ, Skip, OrderBy, and SQL Server 2000
The control is using Skip to get to the records for the specific page that it is supposed to display.
In SQL Server there is no default ordering for queries (unless it's a direct table with a clustered index), so you have to specify an order in the query for the data source. The result of the query has to have a specific ordering; it doesn't make sense to page through a result if the ordering changes from page to page so that you get more or less a random pick of records from the result for each page.
Currently my linq query is ordered...I guess that is not the way forward or am I misunderstanding you?
private object GetMaterialData(string MemberKey, string MaterialType, string MaterialLevel, int Count)
{
ORWeightsDataClassesDataContext db = newORWeightsDataClassesDataContext();
var query = db.tblOnlineReportingCOMPLETEWeights
.Where(x => x.MaterialLevel == MaterialLevel && x.MaterialText == MaterialType && x.MemberId == MemberKey)
.OrderByDescending(x => x.ProductPercentage).Take(Count);
return query;
}

Resources