DMF/DIXF AX 2012 R3 Custom generate method - axapta

I'm working around File Exchange (Export) using Data Import Export Framework (DIXF) , i want to add generate method to Find LineAmount Purchline associated with the receiving line VendPackingSlipTrans from PurchLine table.I create the following script but i need a help :
[DMFTargetTransformationAttribute(true),DMFTargetTransformationDescAttribute("Function that generate LineAmount"),
DMFTargetTransformationSequenceAttribute(11),
DMFTargetTransFieldListAttribute([fieldStr(DMFVendPackingSlipTransEntity,LineAmount)])
]
public container GenerateLineAmount(boolean _stagingToTarget = true)
{
container res;
PurchLine purchLine;
VendPackingSlipTrans vendPackingSlipTrans;
if (_stagingToTarget)
{
select firstOnly purchLine
where purchLine.LineAmount == entity.LineAmount &&
vendPackingSlipTrans.OrigPurchid == purchLine.PurchId &&
vendPackingSlipTrans.PurchaseLineLineNumber == purchLine.LineNumber;
if ( ! purchLine )
{
entity.LineAmount = purchLine.LineAmount ;
entity.insert();
}
}
res = [entity.LineAmount];
return res;
}
I have to export data from ax to file using DMF,so for that i have some field existing in VendPackingSlipTrans so added this fields in staging table but others field exist in other table like LineAmount.I don't know how to add this others fields in staging table. for that in myEnityclass i create generat method to associate field in source table. to staging table

So it seems you want to export VendPackingSlipTrans records with additional information from PurchLine records using a custom entity of the data import/export-Framework (DIXF). If that is correct, there are several problems in your implementation:
logic in if (_stagingToTarget) branch: since the framework can be used for both import and export, _stagingToTarget is used to distinguish between the two. If _stagingToTarget is true, data is imported from the staging table to the Dynamics AX target table. So you need to put the logic in the else branch.
selection of PurchLine record: the current implementation will never select a PurchLine record because values of an uninstantiated VendPackingSlipTrans table variable are used as criteria in the select statement. Also the chosen criteria are wrong, take a look at method purchLine of table VendPackingSlipTrans to see how to get the PurchLine record for a VendPackingSlipTrans record and use the target variable to instantiate the VendPackingSlipTrans table variable.
check if (! purchLine): This check means that if NO PurchLine record could be found with the previous select statement, the LineAmount of this empty record will be used for the staging record. This is wrong, instead you want to use the LineAmount of a record that has been found.
entity.insert(): as I mentioned in the comments, the entity record should not be inserted in a generate method; the framework will take care of the insert
A possible fix of these problems could look like this:
[
DMFTargetTransformationAttribute(true),
DMFTargetTransformationDescAttribute('function that determines LineAmount for export'),
DMFTargetTransformationSequenceAttribute(11),
DMFTargetTransFieldListAttribute([fieldStr(DMFVendPackingSlipTransEntity, LineAmount)])
]
public container GenerateLineAmount(boolean _stagingToTarget = true)
{
container res;
PurchLine purchLine;
VendPackingSlipTrans vendPackingSlipTrans;
if (_stagingToTarget)
{
// this will be executed during import
res = [0.0];
}
else
{
// this will be executed during export
// the target variable contains the VendPackingSlipTrans that is exported
vendPackingSlipTrans = target;
purchLine = vendPackingSlipTrans.purchLine();
if (purchLine)
{
res = [purchLine.LineAmount];
}
}
return res;
}

Related

How to write this conditional request correctly MariaDB

I need to check if a book rating for specific book from specific person exists.
If it does update it, if it doesnt create it.
I am getting a whole bunch of wrong errors for 9th 10th.... 12th parameter missing while I count only 8
My mariaDB version is 10.5.8-MariaDB.
My code:
const createBookRate = async (userId, bookId, rate) => {
const sql = `
SELECT IF(EXISTS( SELECT * from rates WHERE rates.users_id=? AND rates.books_id=? ),
UPDATE rates SET rates.rate=? WHERE rates.users_id=? AND rates.books_id=?,
INSERT INTO rates(users_id, books_id, rate))
VALUE (?,?,?,?,?,?,?,?);
`
const { insertId } = await pool.query(sql, [userId, bookId, rate, userId, bookId, userId, bookId, rate])
const rateEntry = await getBookRate(insertId)
return rateEntry
}
You cannot perform an UPDATE or an INSERT inside the IF clause of a SELECT statement, those must be performed separately.
To perform this in a safe manner, use a transaction and first lock the selected row with SELECT ... FOR UPDATE, then either UPDATE or INSERT it and finally COMMIT the transaction.
If the table has a primary key, you can use INSERT ... ON DUPLICATE KEY UPDATE to either insert the row or update it, depending on whether it exists or not. This allows everything to be done in one step without having to first select the affected rows.

Datagrid sort number - want null last

Is there any way of setting up sort on a datagrid column that is numeric but can be null so that if the user sorts the list it will always show null last
ie
asc would be 1,2,3,null
desc would be 3,2,1,null
Useful as a lot of rows will have null value and if clicking the sort then user is focussed on seeing the info that is thee sorted as above.
Columns can have a custom sorting function that an app supplies.
I'll list an overview and then leave a stackblitz link to a working app so you can reference working code.
First, define a CustomComparator for the app to consume:
import {ClrDatagridComparatorInterface} from "#clr/angular";
class CustomComparator implements ClrDatagridComparatorInterface<any> {
compare(a: any, b: any) {
if (a.key && b.key) {
return a.key - b.key;
} else {
return null;
}
}
}
Next, declare the comparator as a public entity in the component with the datagrid
public customComparator = new CustomComparator();
Finally, update the template to declare usage of the custom comparator on the column that needs it:
<clr-dg-column [clrDgField]="'key'"
[clrDgSortBy]="customComparator">
Key
</clr-dg-column>
Here is a link to a stackblitz with a custom comparator implanted that always return null items last. https://stackblitz.com/edit/so-58020609-custom-sorting

Best way for displaying total Pages for a datasource in Appmaker

I have a Google drive table data source which stores list of open positions. Now in the data source I've set "Query per size" field to 10 so that I can get 10 records per page. I've added a Pager as well to show pagination.
My query is I want to display like "Page 1 of X" to my end users and this X will vary based on certain search filters. What will the best way to achieve this in Appmaker?
I've tried counting total records in a data source as per below code but every time updating that with the search criteria and recounting it is not a proper solution.
//Server side
var newQuery = app.models.Company.newQuery();
var records = newQuery.run();
var totalCount =0;
for(var i=0;i<records.length;i++)
{
totalCount=totalCount+1;
}
return totalCount;
In case you don't have any filters in your table your server code can be as simple as
// Server script
function getPagesCount(pageSize) {
var recordsCount = app.models.MyModel.newQuery().run().length;
var pagesCount = Math.ceil(recordsCount / pageSize);
return pagesCount;
}
As an alternative you can consider creating Calculated Model with a single field PagesCount.
In case you have some filters associated with the table then you'll need to run the query for the pages number with exact same filters.
Most likely the entire setup will not work effectively with Drive Tables since there is no way to query records number without querying records themselves. With Cloud SQL data backend one can create Calculated SQL Model with lightweight native SQL query (here :PageSize is query parameter which should be equal to the query.limit of the actual datasource):
SELECT
Ceil(COUNT(1) / :PageSize) AS RecordsNumber
FROM
TableName
WHERE
...
I've achieved this using Calculated Model as suggested by Pavel.
Steps :
Create a calculated data source with one field count.
In that data source add one parameter searchQuery. This will contain users filter going forward. Currently I have only one search query in which user can search many things. So I've added one parameter only.
In this data source add following server script.
Code:
// Server script
function getTotalRecords(query) {
var receivedQuery = query.parameters.searchQuery;
// console.log('Received query:' + query.parameters.searchQuery);
var records = app.models.Company.newQuery();
records.parameters.SearchText = query.parameters.searchQuery;
if(receivedQuery !== null) {
records.where = '(Name contains? :SearchText or InternalId contains? ' +
':SearchText or LocationList contains? :SearchText )';
}
var recordsCount = records.run().length;
var calculatedModelRecords = [];
var draftRecord = app.models.RecordCount.newRecord();
draftRecord.count = ''+recordsCount;
calculatedModelRecords.push(draftRecord);
return calculatedModelRecords;
}
.
On the Appmaker page bind a label with this data source.
On search query/your filter applied event add following code which Reload this data source and assign value to Parameter.
// Client script
function updateRecordCount(newValue) {
var ds = app.datasources.RecordCount;
ds.query.parameters.searchQuery = newValue;
ds.unload();
ds.load();
}

Pagination in DynamoDB

I have a requirement for to show the search result on the jsp with maxcount of 10 and it should have a pagination to traverse back and forward as pagination functionality.
Dynamodb has a lastevaluatedkey, but it doesn't help to go back to the previous page, though I can move to the next result set by the lastevaluatedKey.
Can anybody please help on this.
I am using Java SPRING and DynamoDB as the stack.
Thanks
Satya
To enable forward/backward, all you need is to keep
the first key, which is hash key + sort key of the first record of the previously returned page (null if you are about to query the first page).
and
the last key of the retrieved page, which is hash key + sort key of the last record of the previously returned page
Then to navigate forward or backward, you need to pass in below parameters in the query request:
Forward: last key as the ExclusiveStartKey, order = ascend
Backward: first key as the ExclusiveStartKey, order = descend
I have achieved this in a project in 2016. DynamoDB might provide some similar convenient APIs now, but I'm not sure as I haven't checked DynamoDB for a long time.
Building on Ray's answer, here's what I did. sortId is the sort key.
// query a page of items and create prev and next cursor
// cursor idea from this article: https://hackernoon.com/guys-were-doing-pagination-wrong-f6c18a91b232
async function queryCursor( cursor) {
const cursor1 = JSON.parse(JSON.stringify(cursor));
const pageResult = await queryPage( cursor1.params, cursor1.pageItems);
const result = {
Items: pageResult.Items,
Count: pageResult.Count
};
if ( cursor.params.ScanIndexForward) {
if (pageResult.LastEvaluatedKey) {
result.nextCursor = JSON.parse(JSON.stringify(cursor));
result.nextCursor.params.ExclusiveStartKey = pageResult.LastEvaluatedKey;
}
if ( cursor.params.ExclusiveStartKey) {
result.prevCursor = JSON.parse(JSON.stringify(cursor));
result.prevCursor.params.ScanIndexForward = !cursor.params.ScanIndexForward;
result.prevCursor.params.ExclusiveStartKey.sortId = pageResult.Items[0].sortId;
}
} else {
if (pageResult.LastEvaluatedKey) {
result.prevCursor = JSON.parse(JSON.stringify(cursor));
result.prevCursor.params.ExclusiveStartKey = pageResult.LastEvaluatedKey;
}
if ( cursor.params.ExclusiveStartKey) {
result.nextCursor = JSON.parse(JSON.stringify(cursor));
result.nextCursor.params.ScanIndexForward = !cursor.params.ScanIndexForward;
result.nextCursor.params.ExclusiveStartKey.sortId = pageResult.Items[0].sortId;
}
}
return result;
}
You will have to keep a record of the previous key in a session var, query string, or something similar you can access later, then execute the query using that key when you want to go backwards. Dynamo does not keep track of that for you.
For a simple stateless forward and reverse navigation with dynamodb check out my answer to a similar question: https://stackoverflow.com/a/64179187/93451.
In summary it returns the reverse navigation history in each response, allowing the user to explicitly move forward or back until either end.
GET /accounts -> first page
GET /accounts?next=A3r0ijKJ8 -> next page
GET /accounts?prev=R4tY69kUI -> previous page

windows service for data insertion

I have created windows service for data-insertion.Time interval is one min.After one min, data insert into table.Data get inserted into table at multiple time.I don't want to that,only one time.How to do that?May I need to check in database wether entry is there or nor if not add.
You can use this query before inserting the data.
IF EXISTS(SELECT * FROM dbo.YourTable WHERE Name = #Name)
RETURN
-- here, after the check, do the INSERT
You might also want to create a UNIQUE INDEX on your Name column to make sure no two rows with the same value exist:
CREATE UNIQUE NONCLUSTERED INDEX UIX_Name
ON dbo.YourTable(Name)
Hope this help you.
//You can do like this in ur code
if (ChkRecordExist() == true)
{
//Do nothing
}
else
{
// insert operation
}
protected bool ChkRecordExist()
{
//here logic for record exist or not.
//if record is exist return true else return false
}

Resources