martes, 11 de febrero de 2014

Exam MB6-869 :: Microsoft Dynamics AX 2012 Development Introduction

Got it!  Yeah!
“Microsoft is a registered trademark of Microsoft Corporation in the United States and other countries."

Below are a few exam tips, from my personal experience.


* Unfortunately no Packt Publishing MB6-869 exam cookbook exists so we have to go to MSDN for our study material.  The links below are no way complete (or we have links with too much information related to the published exam content), but these may help you quickly locate topics covered within the exam for AX 2012.

* Your important first steps would be to take a look at the two Microsoft Development I & II e-learning courses if you have access to them, while a few errors exist in them they are excellent at summarising the MSDN documentation.

* If, like me, you work in a non-English company I suspect that the exam will be a tiny bit more difficult as it’s only available in English, Japanese and Chinese.  Why not change your MorphX settings to English and familiarise yourself with those terms used in the exam?  It took me a while to get used to the changes from the Spanish setting, and I’m a native English guy!

* Pay particular attention to the relative percentages of the exam.  Putting a bit of effort in the Exception handling section is a steal compared to some of the other exam topics that we need to trawl through.  However, even this apparently simple section will have it’s nuances to be aware of. 

* Go play.  For example, the sections related to Valid time state tables, Security, Eventing and Form parts you may never have encountered these in your day-to-day job so you could then either make an excuse to work with them, or go home and construct them on a virtual machine.

* No one will ever accuse you of ‘slacking off’ at work if they find you reading MSDN!  I have found that 15 minutes preparing for the exam during my 11 hour a day working week can provide a great foundation for not only exam study but also for gaining useful knowledge that can be later applied to your daily work tasks/responsibilities.  In fact this whole exercise has given me more confidence when making technical recommendations to other staff.

* If the company that you work for is associated with the Microsoft Partner Network, you can associate their name after passing the exam.  If it’s a serious organisation you should ask your supervisor if they can pay the exam fees for you and give you the time off to actually take the exam, as they will benefit from your certification as well.

* Last minute exam cramming?  Try diving into the fantastic "Microsoft Dynamics AX Topology and architecture diagrams". Or consume like a velociraptor these slide-shows 1, 2, 3.

* Feel free to add any suggestions and corrections to the comments below, as it’s obvious that I haven’t got a 100% handle on some sections…  Good luck!


Microsoft Dynamics AX 2012 Development Introduction (correct as of August 29, 2011)

Microsoft E-Learning (PartnerSource):
* 80304AE: Development II in Microsoft Dynamics AX 2012 (4 Hours)
* 80303AE: Development I in Microsoft Dynamics AX 2012 (3 Hours)

Exam Topics Covered -  The following list includes the topic areas covered on this exam:
* Understanding Dynamics AX 2012 Architecture
* Managing the Data Dictionary
* Managing the User Interface
* Managing Security
* Working with X++ Control Statements
* Managing Objects and Classes
* Accessing the Database
* Managing Exception Handling


+Understanding Dynamics AX 2012 Architecture (13 percent)
- Identify key development features and functionality.
  This topic may include: development workspace; IntelliMorph(1); MorphX(1,2); object-oriented design(1); navigation(1?)
- Demonstrate understanding of the data architecture.
  This topic may include: working with data in forms; sorting records; filtering records(2); finding records
- Demonstrate understanding of architecture components.
  This topic may include: layers; models(1); labels(1); Help system (1,2); reporting (1)
- Work with customization tools.
  This topic may include: using MorphX to customize the user interface; using the X++ editor to develop customizations; identifying best practices(1); using the Type Hierarchy Browser and Type Hierarchy Context tools; using the reverse engineering tool
+Managing the Data Dictionary (13 percent)
- Work with MorphX, the Application Object Tree (AOT), and projects.
  This topic may include: working with development projects; features of the AOT (1); Microsoft Visual Studio projects node(1,2,3); objects in the data dictionary; navigating the AOT and data dictionary
- Work with tables and relations.
  This topic may include: table structure and components(1,2); fields; field groups (1); indexes (1); delete actions(1,2,3); creating tables; creating relations(2, 3, 1, 4, 5); (1) primary keys; foreign keys; surrogate keys
- Work with data types and base enumerations.
  This topic may include: primitive types; extended types(1,2); creating data types(3); using data types(1); creating base enumerations(1,2,3); using base enumerations
- Work with maps and views(1).
  This topic may include: map functionality(1); map advantages; view functionality(1); view advantages
+Managing the User Interface (13 percent)
- Work with menus and menu items.
  This topic may include: creating and using menu items(1,2,3,4); menu functionality(1,2); creating menus
- Manage forms.
  This topic may include: data sources(1); design(1,2,3); document view(3?,1&2?); editing data in a form
- Work with forms.
  This topic may include: form types(2,1); list pages(1) and list page metadata(1); working with the action pane; form parts(1)
+Managing Security (11 percent)
  This topic may include(1,2): identifying key concepts, terms, and benefits(1); working with roles(1), process cycles(1), and duties(1,2); working with privileges(1,2), entry points(1), and permissions(1,2,3)
- Understand security concepts and settings.
  This topic may include: default security settings(1?,2? (search: ‘default’ - see standard roles : -SYSADMIN-, SystemUser, HCMEmployee),3?); sample security settings
- Work with XDS and server enforcement of security.
  This topic may include: server-based code authentication(1,3,2); data security filters; org model(1,2(see section ‘Extensible data security’)); effective date(1,2(select ‘Date Effective Patterns’ to download))
+Working with X++ Control Statements (13 percent)
- Work with variables.
- Work with operators.
- Work with conditional statements(1) and loops(1).
- Work with communication tools.
This topic may include: print; boxes(1); infolog(1!,2,(3),4,5); dialog(3,4,2,1)
+Managing Objects and Classes (12 percent)
- Work with classes(2,1,3), objects, and inheritance.
  This topic may include: defining key attributes(2,1,3!); method access control((1,2,3,4?)); extending a class(1); expression operators for inheritance(1); referencing object methods(2,1); method types(1); inheritance among tables(1,2,3)
- Work with scoping, events, and parameters in X++.
  This topic may include: scope of objects within a class(1,2); events in X++(1)
+Accessing the Database (15 percent)
  This topic may include: table buffers; select statements(1,2); field lists(1,(2)); while select statements; sorting; joins(1,2); cross-company data access(1)
- Manipulate data.
- Work with queries(1).
  This topic may include: executing a query(1); building a query(1,2); QueryBuildDataSource(1); QueryBuildRange(1)
+Managing Exception Handling(1,2) (10 percent)
- Work with exceptions and optimistic concurrency(1) exceptions.
  This topic may include: handling errors(1,2,3,4,5)
- Work with throw and try/catch commands.
  This topic may include: handling errors

miércoles, 29 de enero de 2014

Cube measurement data, or lack there-of

Sometimes when migrating hand-crafted cubes from the development environment to production you get that sinking feeling when no transactions totals appear in the SQL Management Cube Browser.  The culprit in my experience is one of four reasons:
  • No data!  This is not actually a problem, except for live-testing. Sometimes rollouts start by using the sales and ledger module so no one has yet started inputting purchase orders into the production system. Be aware of the issue.
  • RecId differences, usually on the financial dimension sets.
    I really must write another blog post on this, but using AX to publish your cubes is preferred.
  • Virtual company/Table collection issues. As a developer be aware if virtual companies exist and how they are configured with regards to companies and table collections.
    GLOB : US : CON (Contoso DataAreaId)
    Things get worse if there are differences between your development environment and production.  Manually attempting to perform a join on this example in MSDN is going to be difficult so use AOS generated views to do this for you.
  • Eumeration label issues/SRSAnalysisEnums.  THIS issue stung me today, and has done so in the past.  Basically the cubes rely on a per installation generated table called SRSAnalysisEnums to populate the dimension attributes.  There is a great post detailing this for us, the job below will populate this table.  Remember, it may not be populated in some environments.  ALSO remember that if the enumeration does not exist in an AOS perspective, it won't get generated.  Add the table to a new perspective if you have not already do so, and relaunch the generation process. It will take a few minutes.
///If the enum doesn't exist in a Perspective, it won't get added...
///Only 'en-us' values?  See table 'BIUdmTranslations' and check those that require BI labels generated for them.
static void ZZZ_PopulateSRSAnalysisEnums(Args _args)
{;
    BIGenerator::populateSRSAnalysisEnums();
}

If like me you are in a hurry for ONE enumeration that's missing, try this job that inserts or updates the BankAccountHoldStatus value with the enumeration name that you require.
///Only 'en-us' values?  See table 'BIUdmTranslations' and check those that require BI labels generated for them.
static void ZZZ_PopulateSRSAnalysisEnums(Args _args)
{
    //;
    //BIGenerator::populateSRSAnalysisEnums();
    
    // ...Or, populate one concrete enum labels entity
    // ----------------------------------------------------------
    str enumName = 'BankAccountHoldStatus';
    // ----------------------------------------------------------
    
    // Macros and defines
    #AOT
    #Properties
    #SRSModel
    #BIFramework

    SRSAnalysisEnums analysisEnums;

    Set dictEnumSet = new Set(Types::Class);
    Set languageIdSet = new Set(Types::String);

    SetEnumerator dictEnumEnumerator;
    SetEnumerator languageIdEnumerator;

    TreeNode enumNodeRoot = TreeNode::findNode(#BaseEnumsPath);
    TreeNode enumNode;
    TreeNode enumItemNode;

    DictEnum dictEnum;

    int valueIndex;
    str labelId;
    str label;

    SRSEnumName enumItemName;
    SRSEnumValue enumItemValue;

    LanguageId languageId;

    void populateLanguageIdSet()
    {
        BIUdmTranslations translations;
        ;

        BIUdmTranslations::initialize();

        while select LanguageId, Generate from translations where translations.Generate == 1
        {
            languageIdSet.add(translations.LanguageId);
        }

        // add the default language if nothing is currently selected
        if (languageIdSet.elements() == 0)
        {
            languageIdSet.add(@"en-us");
        }
    }

    void addEnumToDictEnumSet(str _enumName)
    {
        DictEnum enum = new DictEnum(enumName2Id(_enumName));
        
        if (enum && !dictEnumSet.in(enum))
        {
            dictEnumSet.add(enum);
        }
    }

    str getLabel(LanguageId langId, str lId, str defaultName)
    {
        str value = #emptyString;
        ;

        if (lId)
        {
            value = SysLabel::labelId2String2(lId, langId);
        }

        if (value == #emptyString)
            value = defaultName;

        if (strLen(value) > #smMaxLengthEnumItemLabel)
        {
            value = subStr(value, 1, #smMaxLengthEnumItemLabel);
        }

        return value;
    }
    
    ;

    populateLanguageIdSet();
        
    addEnumToDictEnumSet(enumName);
    
    // Populate the SRSAnalysisEnums table
    dictEnumEnumerator = dictEnumSet.getEnumerator();

    ttsbegin;

    while (dictEnumEnumerator.moveNext())
    {
        dictEnum = dictEnumEnumerator.current();

        if (dictEnum == null)
        {
            continue;
        }

        enumNode = enumNodeRoot.AOTfindChild(dictEnum.name());

        for (valueIndex = 0 ; valueIndex < dictEnum.values(); valueIndex++)
        {
            labelId = #emptyString;

            enumItemName = dictEnum.index2Symbol(valueIndex);
            enumItemValue = dictEnum.index2Value(valueIndex);

            if (enumNode)
            {
                enumItemNode = enumNode.AOTfindChild(enumItemName);

                if (enumItemNode)
                {
                    labelId = enumItemNode.AOTgetProperty(#PropertyLabel);
                }
            }

            languageIdEnumerator = languageIdSet.getEnumerator();

            while (languageIdEnumerator.moveNext())
            {
                languageId = languageIdEnumerator.current();

                label = getLabel(languageId, labelId, enumItemName);

                select firstfast forupdate EnumName, LanguageId, EnumItemName, EnumItemValue, EnumItemLabel
                    from analysisEnums where analysisEnums.LanguageId == languageId && analysisEnums.EnumName == dictEnum.name() && analysisEnums.EnumItemValue == enumItemValue;

                if (analysisEnums)
                {
                    if (analysisEnums.EnumItemName != enumItemName || analysisEnums.EnumItemLabel != label)
                    {
                        analysisEnums.EnumItemName  = enumItemName;
                        analysisEnums.EnumItemLabel = label;
                        analysisEnums.update();
                    }
                }
                else
                {
                    analysisEnums.EnumName      = dictEnum.name();
                    analysisEnums.LanguageId    = languageId;
                    analysisEnums.EnumItemName  = enumItemName;
                    analysisEnums.EnumItemValue = enumItemValue;
                    analysisEnums.EnumItemLabel = label;

                    analysisEnums.insert();
                }
            }
        }
    }

    ttscommit;
}


lunes, 9 de diciembre de 2013

Cannot create a record in Reporting Services entity cache (SRSModelEntityCache). Entity identifier: XXX, An AX view entity. The record already exists.

Creating a new analysis services project I encountered the following error:
Cannot create a record in Reporting Services entity cache (SRSModelEntityCache). Entity identifier: 7542, An AX view entity. The record already exists.
The message is almost trying to be helpful, providing us the id of the object that is duplicated.
Stepping through my various views associated to the perspectives, I realised that I had done a very silly thing(TM).  I would effectively be adding the same entity to the various cubes twice.  In this case to the shared dimensions perspective.

Perspectives under the microscope

Remember that the wizard for generating cubes adds certain views for us.  The following selection would add the offending BIExchangeRateView.  As you can see from the above image, perhaps I should remove other BI* views as well, although BISampleOrgHierarchyView may be okay.



viernes, 15 de noviembre de 2013

Function SRSTmpTblMarshaller::SendTmpTblToDataProvider has been incorrectly called.

Error:
Function SRSTmpTblMarshaller::SendTmpTblToDataProvider has been incorrectly called.
Solution:
Change the table buffer TableType property used to 'feed' your SSRS report to InMemory.  This is a pain for me as I am working with Tax transactions and wanted the TempDB type, which would avoid storing thousands of rows in the AX client memory.

martes, 1 de octubre de 2013

An export format or a method of payment with an export format must be specified.

An export format or a method of payment with an export format must be specified.

To resolve the error I had to move the current execution point from the CustVendSumForPaym class, constructor method,  "custVendSumForPaym.getLast();" line to avoid looking in the cache (SysLastValue) and retrieving a payment method format that does not exist.  I was asked to rename a file format method text that I had created, and had referenced this class during my testing.  I tried both clearing the cache and restarting the AOS but was unsuccessful attempting to remove the reference to the previously selected payment settings.

The source of my woes.
Edit: Not tried physically deleting the UAC (Ax User cache) file.