Temporary table at runtime - axapta

Is it possible to set table as temporary table at run time in ax 2009?

You mark a record buffer as temporary using the setTmp method. Also remember to call the doInsert method instead of the insert method if you want to avoid the any other updates made in the insert method.
To have a second record buffer refer to the same temporary table use the setTmpData method.
This test job illustrates the use:
static void TmpTest(Args _args)
{
CustTable custTable, custTable2;
;
custTable.setTmp();
custTable.AccountNum = "123Tmp";
custTable.Name = "Temporary?";
custTable.doInsert();
custTable2.setTmp();
custTable2.setTmpData(custTable);
select custTable2 where custTable2.AccountNum == "123Tmp";
info(custTable2.Name);
}

Related

Using InMemory table as a form datasource in Dynamics 365 f&o

I'm obtaining data from an external service and inserting it into an inMemory table (Table_movieTemp), which I use as a datasource on a form (Form_MovieSearch_ds):
[FormControlEventHandler(formControlStr(Form_MovieSearch, FormCommandButtonControl1), FormControlEventType::Clicked)]
public static void FormCommandButtonControl1_OnClicked(FormControl sender, FormControlEventArgs e)
{
FormDataSource Form_MovieSearch_ds = formRun.dataSource();
System.Collections.IEnumerable data = ClassLibrary1.Program::CallRestService();
var enumerator = data.getEnumerator();
while(enumerator.moveNext())
{
MovieRentalService.TmdbMovie item = enumerator.get_current();
Table_movieTemp.Description = item.Description;
Table_movieTemp.ReleaseDate = today();
Table_movieTemp.Title = item.Title;
Table_movieTemp.Rating = item.Rating;
Table_movieTemp.existsAlready = Table_Movie::exist(item.Title);
insertList.add(movieTemp);
}
ttsbegin;
insertList.insertDatabase();
ttscommit;
while select Table_movieTemp
{
info(strFmt("Name: %1,", Table_movieTemp.Title));
}
The while loop I used purely to prove the inserts were succesful.
Afterwards I figure I can call the executeQuery on the form which has my temptable as datasource:
FM_MovieSearch_ds.executeQuery();
This did not work and when I searched google I found a solution where I have to pass the TempTable buffer so that I can link it using 'setTmpTable'.
So I added the following call before calling executeQuery():
formRun.BindTable(movieTemp);
Function on my form:
public void BindTable(FM_MovieTemp _movieTempBuffer)
{
_movieTempBuffer.setTmpData(_movieTempBuffer);
}
Now my code compiles and does not generate runtime errors either, but I still don't see any data. Could someone advice what I miss or do wrong?
The use of in-memory tables in forms has been around for 25 years, and you will find several uses in the standard application.
From the CustVendAgingStatistics form:
void calcAgingStatistics(boolean _research)
{
CustVendAgingStatistics custVendAgingStatistics = CustVendAgingStatistics::construct(linkedCustVendTable, graphData.loadDefName(), graphData.perInvoiceDate());
custVendAgingStatistics.calcStatistic();
tmpAccountSum.setTmpData(custVendAgingStatistics.tmpAccountsum());
if (_research)
{
tmpAccountSum_ds.research();
}
}
Another nice example is found here.
The method:
Insert the records in a separate method, return the local buffer.
In the calling method call setTmpData with the return value.
Research the datasource
In your code I see the use of InsertRecordList, do not use that on in-memory temporary tables, it makes no sense.
Also _movieTempBuffer.setTmpData(_movieTempBuffer) does not do anyting useful as it operates on itself.
Also good style is not do a lot in onClicked methods and other event methods, call proper methods to do the hard work instead.

How to migrate dynamodb data on major table change?

During development structures and requirements change. Key and index settings need to be changed, that might break incremental table update. So my solution so far is to delete the table and recreate it from the cloudformation stack.
But how to solve this problem with a production deployment? Is it possible to automate dynamodb deployment as follows?
Create new table
Migrate data from old table to new table
Delete old table
Yes, it is perfectly possible to automate such a deployment structure. As long as you have code to create a table, it should be fairly straightforward to get all of the data from an old table, change the data, and then upload it all to a new table without any drops in up-time. If you write what language you would like to do such a thing in I can help a bit more.
I've done this before and I've added below a small generified code-sample on how you could do this in Java.
Java method for creating a table given the class of the object type stored in dynamo:
/**
* Creates a single table with its appropriate configuration (CreateTableRequest)
*/
public void createTable(Class tableClass) {
DynamoDBMapper mapper = createMapper(); // you'll need your own function to do this.
ProvisionedThroughput pt = new ProvisionedThroughput(1L, 1L);
CreateTableRequest ctr = mapper.generateCreateTableRequest(tableClass);
ctr.withProvisionedThroughput(new ProvisionedThroughput(1L, 1L));
// Provision throughput and configure projection for secondary indices.
if (ctr.getGlobalSecondaryIndexes() != null) {
for (GlobalSecondaryIndex idx : ctr.getGlobalSecondaryIndexes()) {
if (idx != null) {
idx.withProvisionedThroughput(pt).withProjection(new Projection().withProjectionType("ALL"));
}
}
}
TableUtils.createTableIfNotExists(client, ctr);
}
Java method to delete table:
private static void deleteTable(String tableName) {
AmazonDynamoDB client = AmazonDynamoDBClientBuilder.standard().build();
DynamoDB dynamoDB = new DynamoDB(client);
Table table = dynamoDB.getTable(tableName);
try {
System.out.println("Issuing DeleteTable request for " + tableName);
table.delete();
System.out.println("Waiting for " + tableName + " to be deleted...this may take a while...");
table.waitForDelete();
}
catch (Exception e) {
System.err.println("DeleteTable request failed for " + tableName);
System.err.println(e.getMessage());
}
}
I would scan the whole table and plop all of the content into a List and then map through that list, converting the objects into your new type, and then create a new table of that type but with a different name, push all of your new objects, and then delete the old table after switching any references you might have of the old table to the new one. Unfortunately this does mean that everything consuming your tables are going to need to be able to switch between your two staging tables.

Retrieve data tables from database with stored procedure

Let me explain you in details the scenario that I am having and the solution I am looking for.
Firstfully, I created a stored procedure that outputs simple things such as 2 tables and a message 'don't stop here'"
T-SQL:
USE [mydb]
GO
/****** Object: StoredProcedure [dbo].[BackupDatabase] Script Date: 2/26/2013 11:29:10 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
create PROCEDURE [dbo].[testing]
AS
BEGIN
select 'A' firstname, 'B' lastname;
print 'dont stop here'
select 1 final
END
Up until now I used to retriew the tables in a single manner by using datarowcollection class, and my static method looked like this:
C#:
public static class DataMan
{
public static DataRowCollection SelectData(string sql)
{
SqlDataSource DS = new SqlDataSource(CS, sql);
return ((DataView)DS.Select(DataSourceSelectArguments.Empty)).ToTable().Rows;
}
public static string CS = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
}
where I can easily get what i needed like here, and locate what evver row I wanted:
DataRowCollection people = Util.SelectData("Select * from students")
But now I am planning to create a stored procedure Like I mentioned above and do somthing like this, for instance:
**DataTableCollection** people = Util.SelectData("exec dbo.Testing")
UPDATE:
so I can locate the specific table from my storedprocedure.
I have tried to use DataTable, DataSet, DataTableCollections but no success.I can't use them in proper way.
Please help me
Thank You
Although it can be used in code-behind as you're illustrating here, the SqlDataSource is more typically used in a declarative manner on an ASP.NET markup page. However, given what you've started, when calling a stored procedure, you should set the SqlCommandType to StoredProcedure, supply the name of the procedure to SelectCommand, and return a DataReader. The DataReader, in turn, supports a NextResult() method that you can call to retrieve each discrete result set your procedure provides. Here is a framework of pseudo code that tries to illustrate how you might leverage this:
// pseudo code
void stub()
{
SqlDataSource d = new SqlDataSource(*connection string*);
d.DataSourceMode = SqlDataSourceMode.DataReader;
d.SelectCommandType = SqlDataSourceCommandType.StoredProcedure;
d.SelectCommand = "dbo.Testing";
// set some parameters
d.SelectParameters.Add("Parameter1Name","Parameter1Value"); // must be tailored to your proc!!
d.SelectParameters.Add("Parameter2Name","Parameter2Value"); // must be tailored to SqlDataReader r = (SqlDataReader) d.Select();
while (r.HasRows)
{
while (r.Read())
{
// do something with each row
}
// advance to next result set
r.NextResult();
}
r.Close();
}

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.

How to return multi-table join value from BLL

This question is regarding the ASP.NET webservice that i am creating using the DAL-BLL architecture for my final school project.
I have a stored procedure, which is a select query with an inner join for 2 tables. Hence the stored procedure returns multi-table value. One of my DAL tableAdapter methods accesses this stored procedure. How do i retrieve the return value in the BLL? Do i have to create a class structure similar to the one supposed to be returned by the stored proc? or is there a direct way to achieve the same? Help greatly appreciated. Please let me know if someone needs code applet to get a better understanding. Thanks
Here is some more information:
I am using the SQL dataset (.xsd) in DAL. So i have a datatable called "Insurance", which has a tableAdapter. One of the queries in the adapter references to a stored procedure, which has an inner join. So my SP looks like:
ALTER PROCEDURE dbo.GetInsurancesPaged
(
#startRowIndex int,
#maximumRows int,
#patientID int
)
AS
select * from
(
SELECT Insurance.insuranceID, Insurance.memberID, Insurance.groupID, Insurance.accountType, Insurance.comments, Insurance.patient, Insurance.company, InsuranceCompany.companyID, InsuranceCompany.companyName, InsuranceCompany.address, InsuranceCompany.phone, InsuranceCompany.fax, ROW_NUMBER() over (order by Insurance.dateModified DESC) as ROWRANK
FROM Insurance INNER JOIN InsuranceCompany ON Insurance.company = InsuranceCompany.companyID
WHERE Insurance.patient = #patientID
)
AS DataWithRowNumbers
WHERE ROWRANK > #startRowIndex AND ROWRANK <= (#startRowIndex + #maximumRows)
So this SP returns a datatable which will be a combination of the 2 tables in the inner join. Please correct me if i am wrong.
Now in my BLL, i have:
[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]
public mySys.InsuranceDataTable GetInsurancesPaged(int startRowIndex, int maximumRows, int patientID)
{
return insAdapter.GetInsurancesPaged(startRowIndex, maximumRows, patientID);
}
where insAdapter is an instance of insuranceTableAdapter
This gives an error on execution. I can execute the SP successfully, so i think the problem is only bcz i am trying to return a wrong datatable from the BLL.
Please help me solve this.
If using ADO .Net dataset. The wizard will definetly create a table for the same. now from the dataaccess layer, do the following steps
1. Create a object of dataset. (DLL)
Private YourCustomeDataSetDatatable DataAccess()
{
YourCustomDataSet ds = new YourCustomDataSet(); // also called strongly typed dataset
YourCustomeDataSetDatatable dt = ds.YourCustomeDataSetDatatable ()
YourCustomeDataSetTableAdapter ta = new ds.YourCustomeDataSetTableAdapter (); // table adapter that will be invoked
ta.Fill(dt); // or if you have set to return only you can also use GetData()
}
2. Now in business layer
Private YourCustomeDataSetDatatable DataAccess()
{
// create a object of DLL.
MyDAL myDal = new MyDAL ();
return myDal.DataAccess();
}
Catch this on your UI page by following the creating object of BLL and call the method. Here in BLL you can also do various operations to lowered the codes in you ui and keeping it clean from various manipulations.
Found a solution :)
Finally got it working.
I created a new table adapter using the Dataset designer, and called the SP as one of the queries there. The datatable thus created, has all the fields (from Insurance and InsuranceCompany) included. Now, ASP.NET can detect that the return type is the newly created datatable.
Works like a charm.
If there is a better way to solve this, please comment.
Thank you all for your time.

Resources