Showing posts with label AX2012. Show all posts
Showing posts with label AX2012. Show all posts

Tuesday, 8 August 2017

Difference between view and table

Difference between a view and a base relation: -

Views:
1. This is one type of relation which is not a part of the physical
database.
2. It has no direct or physical relation with the database.
3. Views can be used to provide security mechanism.
4. Modification through a view (e.g. insert, update, delete) generally
not permitted

Base Relation:
1. A base relation is a relation that is not a derived relation.
2. While it can manipulate the conceptual or physical relations stored
in the data.
3. It does not provide security.
4. Modification may be done with a base relation.
We can assign the view, a name & relate it the query expression as
Create View <View Name> as <Query Expression>
Let EMPLOYEE be the relation. We create the table EMPLOYEE as follows:-

Create table EMPLOYEE
(Emp_No integer of null,
Name char (20),
Skill chars (20),
Sal_Rate decimal (10, 2),
DOB date,
Address char (100),)
For a very personal or confidential matter, every user is not
permitted to see the Sal_Rate of an EMPLOYEE. For such users, DBA can
create a view, for example, EMP_VIEW defined as:-

Create view EMP_VIEW as
(Select Emp_No, Name, Skill, DOB, Address
         From EMPLOYEE)

refresh, reread, research, executeQuery - which one to use?

X++ developers seem to be having a lot of trouble with these 4 datasource methods, no matter how senior they are in AX.

1. Common mistakes
Often, developers call 2 of the mentioned methods in the following order:

formDataSource.refresh()
formDataSource.research()

or

formDataSource.reread()
formDataSource.research()

or

formDataSource.research()
formDataSource.executeQuery()

or

formDataSource.research()
formDataSource.refresh() / formDataSource.reread()

All of these are wrong, or at least partially redundant.
Hopefully, after reading the full post, there will be no questions as to why they are wrong. Leave a comment to this post if one of them is still unclear, and I will try to explain in more detail.


2. Refresh
This method basically refreshes the data displayed in the form controls with whatever is stored in the form cache for that particular datasource record. Calling refresh() method will NOT reread the record from the database. So if changes happened to the record in another process, these will not be shown after executing refresh().


refreshEx
Does a redraw of the grid rows, depending on the optional argment for specifying the number of the record to refresh (and this means the actual row number in the grid, which is less useful for AX devs). Special argument values include -1, which means that all records will be redrawn, and -2, which redraws all marked records and records with displayOptions. Default argument value is -2.
This method should be used sparingly, in cases where multiple rows from the grid are updated, resulting in changes in their displayOptions, as an example. So you should avoid using it as a replacement for refresh(), since they actually have completely different implementations in the kernel.
Also, note, that refreshEx() only redraws the grid, so the controls not in the grid might still contain outdated values. Refresh() updates everything, since this is its intention.


3. Reread
Calling reread() will query the database and re-read the current record contents into the datasource form cache. This will not display the changes on the form until a redraw of the grid contents happens (for example, when you navigate away from the row or re-open the form).
You should not use it to refresh the form data if you have through code added or removed records. For this, you would use a different method described below.


How are these 2 methods commonly used?
Usually, when you change some values in the current record through some code (for example, when the user clicks on a button), and update the database by calling update method on the table buffer, you would want to show the user the changes that happened.
In this case, you would call reread() method to update the datasource form cache with the values from the database (this will not update the screen), and then call refresh() to actually redraw the grid and show the changes to the user.


Clicking buttons with SaveRecord == Yes
Each button has a property SaveRecord, which is by default set to Yes. Whenever you click a button, the changes you have done in the current record are saved to the database. So calling reread will not restore the original record values, as some expect. If that is the user expectation, you as a developer should set the property to No.


4. Research
Calling research() will rerun the existing form query against the database, therefore updating the list with new/removed records as well as updating all existing rows. This will honor any existing filters and sorting on the form, that were set by the user.


Research(true)
The research method starting with AX 2009 accepts an optional boolean argument _retainPosition. If you call research(true), the cursor position in the grid will be preserved after the data has been refreshed. This is an extremely useful addition, which solves most of the problems with cursor positioning (findRecord method is the alternative, but this method is very slow).


5. ExecuteQuery
Calling executeQuery() will also rerun the query and update/add/delete the rows in the grid. The difference in behavior from research is described below.
ExecuteQuery should be used if you have modified the query in your code and need to refresh the form to display the data based on the updated query.


formDataSource.queryRun().query() vs formDataSource.query()
An important thing to mention here is that the form has 2 instances of the query object - one is the original datasource query (stored in formDataSource.query()), and the other is the currently used query with any user filters applied (stored in formDataSource.queryRun().query()).
When the research method is called, a new instance of the queryRun is created, using the formDataSource.queryRun().query() as the basis. Therefore, if the user has set up some filters on the displayed data, those will be preserved.
This is useful, for example, when multiple users work with a certain form, each user has his own filters set up for displaying only relevant data, and rows get inserted into the underlying table externally (for example, through AIF).
Calling executeQuery, on the other hand, will use the original query as the basis, therefore removing any user filters.
This is a distinction that everyone should understand when using research/executeQuery methods in order to prevent possible collisions with the user filters when updating the query.

Importing a General Journal using Data Import/Export Framework AX 2012

Here is a tutorial on how to configure Dynamics AX 2012 to import a general journal from a CSV file. The steps below are using Contoso demo data.
  1. Create a new folder on the root of the C: Drive and name it “DIEF”:
  2. Navigate to Data import export framework | Setup | Data import export framework parameters. Click “Browse” next to “Shared working directory” and select the “DIEF” folder we created. Once selected, click “Validate”.
  3. Close the “Data import export framework parameters” form.
  4. Go to Data import export framework | Setup | Source data formats. Enter “GLJOURNAL” for the “Source name” and “Type” = “File. In the parameters on the right side, enter “File format” = “Delimited”, “First row header” = TRUE, “Row delimiter” = “{CR}{LF}”, “Column delimiter” = “Comma {,}”, “Text Qualifier” = “*”, and “Role separator” = “;”. Click “Application”, and then select “CostCenter”, “Department”, and “ExpensePurpose”. Enter “CostCenter-Department-ExpensePurpose” for the “Dimension format” value.

  5. Go to Data import export framework | Setup | Target entities. Click “New” and enter “Entity type” = “Entity”, “Entity” = “Custom”, “Entity name” = “GLJOURNAL”, “Staging table” = “DMFLedgerJournalEntity”, “Entity class” = “DMFLedgerBalanceEntityClass”, and “Target entity” = “DMFLedgerJournalTransEntity”. Close the “Target entites” form.
  6. Go to Data import export framework | Common | Processing group. Type “GLJOURNAL” for the “Group name”, Ctrl+S to save, and click “Entities”. 
  7. On the “Select entities for processing group” form, enter “GLJOURNAL” for both the “Entity name” and the “Source data format”. Click “Generate source file”.
  8. On the “Wizard” form, click “Next”. For the “Display data” fields, select the following and put them in the following sequence: JournalName, JournalNum, LineNum, CurrencyCode, TransDate, Voucher, AccountType, LedgerDimension, AmountCurDebit, AmountCurCredit, OffsetAccountType, OffsetLedgerDimension. Click “Generate sample file”.
  9. A .txt file should open, and save it to the root of the C: drive.
  10. Click “Finish” on the “Wizard” form. Close the “Select entities for processing group” form. Close the “Processing group” form.
  11. Go to General ledger | Setup | General ledger parameters. Click “Number sequences”. Right-click “Gene_10” next to “Journal batch number” and click “View details”.
  12. Click “Edit”, change the “_010” to “JN”, and click “Move up”. Click the “General” fast tab and note the “Next” value, in my case “JN000421”.
  13. Close the “Number sequences” form and the “General ledger parameters” form.
  14. Navigate to General ledger | Setup | Journals | Journal names. Select “GenJrn” and right-click the “Acco_18” next to “Voucher series”, and then click “View details”.
  15. On the “Number sequences” form, click “Edit”. In the “Segments” fast tab, click “Add”, select “Constant” for the “Segment”, and type “VN” for “Value”. Move this new segment to the top by clicking “Move up”. Note the next number in the series. In my case, “VN00000038”.
  16. Close all forms.
  17. Open Excel. Click File | Open. Navigate to the C: drive and select the “GLJOURNAL.txt” file (You may need to change the drop menu to “All Files (*.*)”)
  18. On the “Text Import Wizard” form, click “Delimited” and click “Next”. Check the box for “Comma” and click “Finish”.
  19. In line 2, enter the following values for each header:
    1. JournalName = GenJrn
    2. JournalNum = JN000421 (Value from step 12)
    3. LineNum = 1
    4. CurrencyCode = USD
    5. TransDate = 8/19/2013
    6. Voucher = VN00000038 (Value from step 16)
    7. AccountType = Ledger
    8. LedgerDimension = 110180-OU_1-OU_3566-Training
    9. AmountCurDebit = 10
    10. OffsetAccountType = Ledger
    11. OffsetLedgerDimension = 110101-OU_1-OU_3566-Training
  20. Click File | Save As. Click “CSV (Comma delimited)” for the “Save as type” drop-menu.
  21. Close Excel.
  22. Go to Data import export framework | Common | Processing group. Select the line for “GLJOURNAL” and click “Entities”.
  23. Click the folder icon next to “Sample file path”, and select the .csv file from step 20. Click “Generate source mapping”. Close the infolog.
  24. Close the “Select entities for processing group” form.
  25. On the “Processing group” form, select the line for “GLJOURNAL” and click “Get staging data”.
  26. A form for “Create a job ID for the staging data job” should open and populate with a “Job ID”. Click “OK”.
  27. On the “Staging data execution” form, click “Preview”. Verify the columns are correct, and then click “Run”.
  28. Close the infolog.
  29. On the “Processing group” form, click “Copy data to target”. Select the “Job ID” created earlier, and click “OK”. On the “Target data execution” form, click “Run”, then click “OK”.
  30. Close the Infolog.
  31. Go to General ledger | Journals | General journal. Locate the imported journal, and click “Lines”.
  32. Notice the values imported properly, and click Post | Post. The journal posts successfully.

Using UI Builder Class to Develop SSRS Reports in Microsoft Dynamics AX 2012

UI Builder Class Overview

User Interface (UI) Builder Class is used to define the layout of the parameter dialog box that opens before a report is run in Microsoft Dynamics AX. It is used to add the customizations as well as additional fields in the dialog.
Following are the scenarios where UI Builder Class can be used:
  1. Grouping dialog fields
  2. Overriding dialog field events
  3. Adding a customized lookup to a dialog field
  4. Binding dialog fields with Report contract parameters
  5. Changing the layout of the dialog
  6. Adding custom controls to the dialog
To create a UI builder class, extend it with SrsReportDataContractUIBuilder.

Pre-requisites

  1. Microsoft Dynamics AX 2012
  2. Reporting services extensions must be installed in Dynamics AX
  3. Report contract class

Sample UI Builder Class

  1. Create a new class. Open AOT à Classes
  2. Right Click on Classes and select New Class. Name it as SSRSDemoUIBuilder
  3. UI builder class example in microsoft dynamics ax 2012
  4. Open the Class declaration by right clicking on it and selecting View code
  5. UI builder class example in microsoft dynamics ax 2012
  6. Write the following code
  7. public class SSRSDemoUIBuilder extends SrsReportDataContractUIBuilder
    {
    
    }
  8. Now open the contract class and add the following line to the header of the class. It will tell the contract class to build the parameter dialog. In other words, it will link the UI Builder Class with the contract class.
SysOperationContractProcessingAttribute(classStr(SSRSDemoUIBuilder))

Examples of UI Builder Class Usage

Based on different scenarios, different methods are overridden as shown in the following examples:
  1. Grouping the dialog fields/Changing the layout of the dialog/Adding custom controls to the dialog
    • To customize the layout and add custom fields, override the build as shown below:
    • public void build()
      {
          DialogGroup dlgGrp;    
      
          //get the current dialog
          Dialog      dlg = this.dialog();       
      
          //make required modifications to the dialog
          dlgGrp = dlg.addGroup('Dates');  
          dlgGrp.columns(2);   
          dlg.addField(identifierStr(FromDate));
          dlg.addField(identifierStr(ToDate));    
              
          dlgGrp = dlg.addGroup('Customer');  
          dlg.addField(identifierStr(CustAccount));    
      }
      
    • ThIS build method is called by the report framework to generate the layout of the dialog.
  2. Binding dialog fields with Report contract parameters
    • Write the following code in the build method:
    //get the report data contract object
    contract = this.dataContractObject();
        
    //associate dialog field with data contract method
    this.addDialogField(methodStr(SSRSDemoContract,parmCustGroupId), contract);
  3. Overriding dialog field events/Adding a customized lookup to a dialog field
  • To add a customized lookup or to override a control method, create a new method containing the business logic. The new method must have the same signature as the method you want to override.
  • Then, override the postBuild method and register the method to override with the new method created.
  • In the following example, the lookup method of a field is to be overridden. To do this, create a new method lookupCustGroup and add the following code:
  • public void lookupCustGroup(FormStringControl _formStringControl)
    {    
        Query query = new Query();
        QueryBuildDataSource DS;    
        SysTableLookup sysTablelookup;
    
        //create a table lookup    
        sysTablelookup = SysTableLookup::newParameters(tableNum(CustGroup),_formStringControl);
        sysTablelookup.addLookupfield(fieldNum(CustGroup,CustGroup));
        sysTablelookup.addLookupfield(fieldNum(CustGroup,Name));
    
        //create a query
        DS = query.addDataSource(tableNum(CustGroup));
        DS.addRange(fieldNum(CustGroup,PaymTermId)).value('N030');
    
        //assign the query and call lookup
        sysTablelookup.parmQuery(query);
        sysTablelookup.performFormLookup();
    }
  • Now, override the postBuild method and write the following code:
  • public void postBuild()
    {
        DialogField dlgCustGroup;
        
        super();
        
        //get the field to override by providing the data contract object and the associated attribute/method
        dlgCustGroup = this.bindInfo().getDialogField(this.dataContractObject(),
                    methodStr(SSRSDemoContract,parmCustGroupId));
    
        //register the method we want to override
        dlgCustGroup.registerOverrideMethod(
              methodStr(FormStringControl, lookup),
              methodStr(SSRSDemoUIBuilder,lookupCustGroup),
              this);    
    }
    
  • bindInfo returns an object of type SysOperationUIBindInfo. It contains information about the dialog controls bounded to a report contract.
  • postBuild method is called when dialog is created.

Vendors Merge In Microsoft Dynamics AX 2012

static void vendorsMerge(Args _args)
{
    VendTable                                   vendTable;
    VendTable                                   vendTableDelete;
    PurchJournalAutoSummary                     journalSummary;
    RetailVendTable                             retailVendTable;

    DimensionAttributeValue                     dimensionAttributeValue;
    DimensionAttributeLevelValue                dimensionAttributeLevelValue;
    DimensionAttributeValueGroup                dimensionAttributeValueGroup;
    DimensionAttributeValueCombination          dimensionAttributeValueCombination;
    DimensionAttributeValueGroupCombination     dimensionAttributeValueGroupCombination;

    #define.vend('1003')
    #define.vendDelete('US_TX_003')

    ttsbegin;
    delete_from journalSummary
        where journalSummary.VendAccount ==  #vendDelete;
    delete_from retailVendTable
        where retailVendTable.AccountNum == #vend;

    select firstonly forupdate vendTableDelete
        where vendTableDelete.AccountNum == #vendDelete;

    select firstonly forupdate vendTable
        where vendTable.AccountNum == #vend;

    select firstonly forupdate dimensionAttributeValueGroup
        join dimensionAttributeLevelValue
            where dimensionAttributeValueGroup.RecId == dimensionAttributeLevelValue.DimensionAttributeValueGroup
               && dimensionAttributeLevelValue.DisplayValue == #vendDelete;
    dimensionAttributeValueGroup.delete();

    select firstonly forupdate dimensionAttributeValue
        join dimensionAttributeLevelValue
            where dimensionAttributeValue.RecId == dimensionAttributeLevelValue.dimensionAttributeValue
               && dimensionAttributeLevelValue.DisplayValue == #vendDelete;
    dimensionAttributeValue.delete();

    select firstonly forupdate dimensionAttributeLevelValue
        where dimensionAttributeLevelValue.DisplayValue == #vendDelete;
    dimensionAttributeLevelValue.delete();

    select firstonly forupdate dimensionAttributeValueGroupCombination
        join dimensionAttributeValueCombination
            where dimensionAttributeValueCombination.RecId == dimensionAttributeValueGroupCombination.DimensionAttributeValueCombination
               && dimensionAttributeValueCombination.DisplayValue == #vendDelete;
    dimensionAttributeValueGroupCombination.delete();

    select firstonly forupdate dimensionAttributeValueCombination
        where dimensionAttributeValueCombination.DisplayValue == #vendDelete;
    dimensionAttributeValueCombination.delete();

    vendTableDelete.merge(vendTable);
    vendTable.doUpdate();
    vendTableDelete.doDelete();
    ttscommit;
    info("Vendor merging successfull");
}