Debug BP errors in Dynamics AX 2012

With Dynamics AX 2012, some new BP errors have been introduced. Often, while fixing BP errors, I turn to the List of Best Practice Error and Warning Messages page on MSDN for help.

But what if you are getting a BP error and there is no clear description on how to fix it. In such scenarios, I always debug the BP error and try to see what is causing this BP error in the first place.

Let us do this with a simple example.

On a Dynamics AX 2012 machine, Create a table with just two fields, ItemId and Name.

Create a normal relation on the table with InventTable on ItemId == InventTable.ItemId

On running the BP check on this table, among other BP errors, you will receive this new to Dynamics AX 2012 BP error - Only foreign key constraints are allowed on this table.

Some of you may know the reason why this BP error is being thrown. For those who do not know the reason, please hold on to that doubt, I'll explain it shortly in the end. Let us get back to the original topic of the post, how to debug this BP error and find out why it is being thrown?

If you look at the compiler output window, you will find a column titled Diagnostic ID. This is new in Dynamics AX 2012. So what does this column specify? Well, the diagnostic ID is the value of the BP error macro being thrown.

In our case, the diagnostic ID for the BP error Only foreign key constraints are allowed on this table is 839.

Now, let us open the SysBPCheck macro and search for 839. This is what we will find
#define.BPErrorTableNaturalKeyWithRecID(839)    // RecID field cannot be part of the NaturalKey index.

Ok, so this means that somewhere in code, a BP error is being raised with this macro. Copy the macro name and search in the BP classes of the object type.

The BP classes start with SysBPCheck. In our case, since the error was being thrown on a table, we will search in all the classes related to tables.
As seen in the image above, we found two instances of the macro in code. Open both the instances and check for the error message. The error in the second instance matches with the error we saw in the compiler output. So our error is being thrown from this location. If you want to confirm, you can set a break point here and run the BP check again on the table, the break point will be hit.
Now if you scroll the code a little up, you will see why this condition is being hit. The code is
//If we need to Enforce RelationRules, Check to see if this is FK relation.
            //If it is not and FK check is not skipped, throw BP error if:
            //1. Not a Migrated relation (OR)
            //2. There is no Covering PKAK Index on the related Table covering the related fields in the relation

            if(sysDictTable.enforceRelationRules())
            {
                if(!foreignKeyRelation && !skipFKCheck)
                {
                    //Dont Relax the BP error if:
                    //1. if the relation is not EDT relation (OR)
                    //2. The relation has ThisFieldFixed relationLines(OR)
                    //3. The relation has all Normal Field relations (OR)
                    //4. if the related Fields is not covered by PK or AK index in the related Table

                    if(!dictRelation.EDTRelation() || nonConfirmingRelationLines || (conLen(fixedFieldList)==0) || !relatedFieldsCoveredByPKAKIndex(joinDictTable,normalFieldList,fixedFieldList))
                    {
                        sysBPCheck.addError(#BPErrorTableNaturalKeyWithRecID,i,0,"@SYS129769");  //use i as line number to avoid reporting identical BP errors, if multiple relations have the same error.
                    }
                }
            }
So, in our case we see that this is not a foreign key relation hence the condition is satisfied and the error is thrown. I'll not go in the detail of the code, you can debug and find out what it means.

For those of you who were wondering the reason for this BP error, it is because we should create a new Foreign key based relation instead of a normal relation.

Simply put, when you drag and drop the ItemID EDT on the table, it will ask for your confirmation to add the relation on the EDT. The dialog will be like this
Press Yes and a Foreign key based relation will be created. If you press No and want to create the relation manually, make sure you create a Foreign key based relation and not a normal relation.

Both the normal and foreign key relation looks the same and it is visually difficult to differnetiate between them. So, if you ever encounter the above mentioned BP and have a relation defined, delete and recreate a new foreign key relation.

I hope this post was helpful. Please feel free to send me your queries and feedback.

Thats all for today, check back soon for more.

Comments

Anonymous said…
Great, thanks for the information.
Anonymous said…
should add +1 to the Macro number because 839 is

.#define.BPErrorTableNaturalKeyWithRecID(839)

and we actually need 840.

thanks
Anonymous said…
Thanks Zubair. Very informative.

Small addition is that if you have fields like Recid and you don't want to create a EDT then to resolve this issue you can create a new relation by Relations -> New Relations -> Foreign Key -> Primary Key based. Then the fields are automatically inserted and relation is created just by triggering the relation type. This will also resolve the issue

Popular posts from this blog

How to add empty ranges in query

Get selected records in Dynamics AX 2012

How to refer to form controls in code without setting the AutoDeclaration property in Dynamics AX?