Monday, November 14, 2011

Ignore IDs During Code Compare

If any of you have done a code compare, comparing one XPO to the matching objects within the AOT, you may have noticed that in most cases the ID values of various nodes/sub-nodes don't match.  This is only partially correct, the node itself may match identically except the ID property, which doesn't cause a change in functionality anyways.  This annoyingly forces you to click through each item to verify that each node IS in fact identical.  I have developed a solution, an option to ignore these ID properties as a checkbox in the Advanced tab of the Compare form.

Let's take the Address table for example.  If we have an XPO that includes the Address table and we attempt to compare it with the object in the AOT, we will see "differences" like this:


As we can see, it shows a difference in every single field and index on the table.  What happens is when an object is exported to an XPO, it does not retain the ID values as they really don't change how it functions.  When importing from an XPO and comparing, the IDs in the XPO default to 0, thus showing the difference.

Normally this isn't a bad thing, but it gives you the feeling that there are truly differences that change the functionality.  It becomes a pain to filter through each node and double check each to see the real differences.  More often than one would think, a real difference slips by unnoticed because of the mass amount of false positives in changes, thus promoting code to Production without truly meaning to.

I proposed a solution to add an option to the SysCompareForm to ignore ID properties (as shown below).


By default, I have the checkbox checked to ignore the IDs, you may choose to change that as needed per your business's requirements.  The screenshot below shows how tidy it looks after ignoring the ID properties.



DOWNLOAD XPO HERE and Enjoy!

Bug Reported (2/27/2012): Ineffective towards EDTs and Enums, still shows the comparison.

Friday, November 4, 2011

Dynamics AX Pain Points

I've been developing in DAX for about 3 years and over those years I have generated a big written list of things that I wish would be better.  Granted, I am working in Dynamics AX 4.0, so there may have been things that have been fixed in future versions, but nonetheless I compiled a list.  Some of these are minor, some of them are big.  Some of them have workarounds, and some do not.

You ask: Why are you blogging about it?  Well, I did mention some of these written notes are years old; to be honest, it's so old the ink is starting to fade and I wanted to make an electronic copy and elaborate on them and continue to do so when I run across them.  I also hope to through time provide workarounds for these pain points.

I apologize, this is probably going to be a post that I will update from time to time, but if you have any questions, possibly about a topic that I mention there is a workaround but I haven't gotten around to explaining it, feel free to comment below and I'll do my best to either quick blog the workaround, or respond to your comment.

DAX Kernel 4.0.2503.854
DAX Application 4.0.2503.57

Issues (with Workarounds)
  • When trying to compare code from an XPO to an object in the AOT, through the Import form, right-clicking the object in the Details frame causes a Synchronize on that object, which possibly can cause a table to rebuild it's indexes
    • Workaround - It's a hack but it could save your job
  • Code compare has no option to ignore checking differences in Object IDs
    • Solution - Custom checkbox within Compare form
  • Containers are stored in the database as BLOBs, impossible to reference from outside DAX
    • Solution - I have developed two SQL user-defined functions that allow you to conpeek() outside of DAX
  • Inability to filter enums within a ComboBox control (workaround is possible, blog post soon)
  • Some enums aren't available in the SRSModelEntityCache and SRSAnalysisEnums
    • Solution - Must add your wanted Enums to a Perspective and update the model
  • Unable to update/insert data from outside DAX (Workaround possible, blog post soon)
  • Unable to reorder Data Sources within a Form after you already created them in VSS.  They only appear to reorder in the AOT but still function during runtime the same as the original order. Workaround soon - It's not pretty
  • When using VSS and creating new Jobs, the original/default name of the Job still retains as the Name property even after you change it in the code.  Workaround, this one isn't pretty either.
Bugs (Issues with no workaround found)
  • If you have multiple AOS instances for one database, sometimes compiling the code does NOT push the change to all the AOS's (probably a caching issue)
  • The MorphX editor closes and the AOT node collapses when you Check Out that object from VSS
  • The Compile window does not clear when recompiling
  • Soft breakpoints don't always work, most often in forms, because they are client ran
  • Code Profiler affects the outcome sometimes, and misses some calls, hardly useful but good in theory
  • Dragging and dropping nodes in the AOT doesn't consistently allow you to re-order nodes, you have to use Alt+Up/Down instead (Explanation)
  • Can't drag and drop objects from a project to another project without having the source project checked out, should just copy the reference in the new without trying to pull it out of the source project
  • If I have two windows both are not maximized, I maximize one, then I close it, the second window magically assumes it should be maximized as well.  And sometimes when clicking back and forth from window to window, sometimes it automatically maximizes. Why? (Seems to happen a lot with the "Find" form)
  • Some tables, for example (TaxBook/SalesPurchCycle/PBARulePBAId2ConsId/COSPlanTable), when you change the primary key or clustered index, the change is not reflected in the database
  • When importing two objects that having elements that reference each other, there is an error saying that an object doesn't exist (forces the user to import multiple times to finally get it all)
  • If a Field Group changes in a table (changing order or adding new fields in a specific order), any groups within a form (or report I presume) will not refresh and put the fields in that correct order even after a compile
  • If you create a field on a table, name it something, and later realize that it is the wrong type and delete and readd that field, same name but with a different type, fieldnum() will always return the original fieldId, not the new one.
Suggestions & Gripes
  • RecordSortedList should have the option to sort in descending order
  • When using multiples instances of AOS's, the RecId's issued may not always be in order of when it is inserted (The number sequencing behind RecId's has the option to batch request a set of RecId's at a time but may not use them in order).  Why not just use an auto-increment identity column and let the database handle what it does best?
  • date2str is a ridiculous function.  There should be Enums to go along with the parameters that date2str takes in.  Having to hard-code 213 for US date standards is not cool.
  • EDTs should have a property for data length, display length doesn't enforce what goes in the database
  • DAX is shipped with numerous instances where there are relations on varchar type fields, I was always taught that is a big no-no, a big performance degradation
  • DAX doesn't have a good event model
  • There's no good built-in way to listen to keystrokes, the workaround would be to monitor the task() method on forms, but the int values of the keystrokes that are hit are unknown.
  • No way to control and specify Shortcut keys (for buttons in forms)
  • Lack of a good API reference, MSDN is hardly sufficient (I want to know the order in which the kernel calls certain methods in Forms/Data Sources/RunBaseBatch/Reports/etc.)
  • Date and time are stored separately, why not a DateTime type, databases have been able to handle this for years
  • DataAreaId is always the first field in every index created, it makes the histograms of the statistics of the database not very useful when most companies have only one Company/DataArea
  • Projects really only consist of pointers to the real objects in the AOT, not cloned copies of the object
  • Can't check in/out a project from the Project window when you have it open
  • When compiling code, if you are calling into a method that accepts a string EDT as a parameter, it should at least show a warning when the size of that parameter being passed in could be larger than what the method is expecting to accept, otherwise truncation is possible
  • Why do we have to define all variables first and why the extra semi-colon?
  • Inability to overload methods
  • VSS is the only option for source control, in 4.0 (allows for no branching or merging/does not track objects that were deleted or renamed/no option for TFS/checkout time seems to grow significantly with the number of versions)
  • The database is not relational, each table is it's own separate entity
  • SysLastValue and it's caching mechanism, why does this need to be so complicated?
  • The layer architecture is a good idea, but when MS releases patches, we can't jam code into objects that exist in higher layers
  • Why do edit/display methods have to call the database continuously?  Debugging these are horrible.
  • No relations on Views?
  • Users are not able to create enum values, this forces most developers to make master tables so the user can manage it.  So why have enums at this point?
  • Because of SOX and PCI requirements, I wish there was a way to have read-only access to code vs no access to code (most Production environments can't allow developers access to change code per PCI/SOX)
  • Why isn't there a way to test security as another user (alias their security settings similar to SharePoint)
  • DAX doesn't have a HAVING clause, forced to create a temp table to store the data and filter the data in a WHERE
  • DAX has no concept of NULL, makes it nearly impossible to LEFT OUTER JOIN
  • Cannot seem to get more than one LEFT OUTER JOIN to work in one QueryRun object.
  • The order of DataSources within a form impacts the underlying queries, expectations can vary
  • Must have temporary tables as the innermost table vs being a table that is joining to another table? I understand why, but why can't DAX just create real temporary tables in the database so it can join to it any way we want?
  • Number sequencing is heavy on the database, why not have a separate table that stores the TableId, FieldId, and some sort pattern to display the identity column (ex. SalesId would be SO%)
  • Number Sequences are created by writing code? What? If we're so determined to bypass a standard that SQL databases have had for decades for identity columns (autoincrement); why not make it easier by having Number Sequences as an item in the AOT?  That way, you could have a field property to specify a Number Sequence object to use, and it could increment automatically?
  • Add a countdistinct(_field_) aggregate function to perform a COUNT(distinct _field_).  count() only includes a count of records, not unique records, not very useful.
  • any2str function converts an anytype object to a string ONLY if that anytype object is of type string....what? (Explanation)
  • Unable to drag objects from one project to another (copy) without having the source project checked out.
  • If new fields are added to a Field Group in a Table, any Form that uses it does add the new fields correctly, however not in the order in which the Field Group shows it, even if you compile it.
  • There is no way to compare your checked out (while working on a change) version of the code to the latest version.  This would be very handy, especially if you have multiple developers in the same environment and you want to see what the other developers have changed. (Fixed in 2012)