Sunday, February 6, 2011

Usage data explained

Usage data is incredibly important to the end user, and very delicate as far as data goes in my opinion.  I'll expand on why I think it's delicate later on in this post.  This post will detail what I've discovered about it, but is limited due to the fact that usage data is system level and mostly hidden.

As a developer, I am clearing my usage data regularly without giving it a second thought.  I once made the mistake of clearing all of a user's usage data when they were experiencing a strange issue with a form.  They lost all of their stored queries, user-specific form customizations, ad-hoc reports, pre-filled in data, etc.  Let's just say I haven't made that same mistake twice.

Why I researched usage data:
We have some BUS-layer IP (intellectual property) that we have sold at a client.  It was sold with the understanding of both parties that it is in development, and a very living/breathing product.  They received a big price break for being the guinea pigs on the software.  Anyway, some objects were heavily customized, such as the SalesTable form.

We started phase 1 on a version IP 1.0, and we were live and operating while phase 2 was developed.  We deployed phase 2 successfully, from a technical standpoint.  The system looks exactly as I, the developer, would expect, however many users were complaining that all of their Intellimorph customizations to certain objects (SalesTable) were gone.

How usage data is stored:
Usage data is stored in a single hidden system table called SysLastValue.  It has the following main fields
  • userId
  • recordType - UtilElementsType::*
  • elementName
  • designName
  • isKernel
  • company
  • value - Container, this is where the important stuff is
Where usage data gets difficult:
Usage data, according to MS, is different for pretty much every object.  I like to think of it as a custom, system level pack/unpack.  So unfortunately, this means you really can't just modify usage data without knowing the underlying code structure.  I personally think that there is some sort of framework for these objects once they're past the sys layer.  Like a custom pack method for SalesTable with a generic pack-other method for any custom modifications.

What you can do with this info:
You can backup usage data and copy it to other users.  If you have some custom Intellimorph modifications to a form, for example, you can run a quick job to copy your saved settings to every user in the system.  You can make a "golden user" of sorts where you make modifications to forms, then copy to other users.  I'll be posting a neat code example shortly on how to use recursion, containers, and tree nodes to view usage data shortly.

This is what I've come to understand of usage data from my experiences only.  My viewpoint is limited because the code is unavailable.


  1. Nice post, Alex!
    An example would be a great idea.
    We're now observing some unexplained loss of usage data after the last build we did...

    1. This is sort of hard to do an example for, but I can tell you how you might be able to figure out what went wrong. You need to setup a before and after system.

      In the before system, go to the AOT>Forms>SysLastValue, then right-click on the SysLastValue DATASOURCE, and go to Add-Ins>Table Browser. This is a sneaky way to view hidden tables. Find the object that you're having usage data issues with in this table for a user.

      Under the value column, it looks blank, but click on it, then click the lookup/dropdown, and it will invoke "conview(...)" so you can see the contents of the usage data in a tree view.

      Do this in your after system too and compare the difference. They might look identical, but that's because the usage data doesn't match the new form, so reset the usage data for that object for a user, then re-make your changes by hand, then look at the usage data again.

      This will let you see how the system expects the usage data to be stored. If you really need a fix, you can create a job to repair usage data for specific objects if you can figure out the change.

    2. Oh, also, in the "before" system, you don't really need to concern yourself with the code at all...just the database before your changes, because you only need to see the value in that container.

      So no need to try and revert code, etc. Just a previous database backup that has the one record in it.