«

»

Print this Post

NAV Extensions – Generic Code To Migrate Data When Upgrading Extensions

UPDATE: Updated info can be found in this post.

This is not a post on how Extensions work – I guess there is a lot of material out there that already handles Extensions. And if you don’t find any .. just check YouTube for a few video’s, like:

This small post is about migrating data from one version of your extension to another.

When you’re upgrading an extension, you’re actually doing that in a few steps:

  1. Publish a new version of your extension
  2. Uninstall the current installed version of the extension in Tenant X
  3. Install the new published version of the extension in Tenant X

Now, uninstalling an extension means it’s going to kill any change you did on the application, which also means it’s going to remove fields, and even entire tables.

What happens with the data then?

Well, to not go too deep into details: your data is moved to a new table in the SQL Server Database, like you see here:

The $AppData$… table is holding all the data with the fields and values that you would have lost when uninstalling the Extension.

So how do I get the data in?

Well, it’s all quite well explained on MSDN: Extending Microsoft Dynamics NAV Using Extension Packages. In short, you have to create a codeunit that holds at least one of these global function names:

  • OnNavAppUpgradePerDatabase()
  • OnNavAppUpgradePerCompany()

Indeed: they need to exist in your extension (part of your delta’s) as global functions. Weird approach, isn’t it? But it works – and you can even guess how it works: it’s going to call the “..PerDatabase” only once per database (so, only once), and the other once in each company. That’s where you will put your upgrade code.

How do I get to the data in code?

To get to your saved data, you have the statement “NAVAPP.GETARCHIVERECORDREF”. You need to provide a tableID, and a RecRef variable. The latter will contain the archived data of the table you mentioned. So this needs to be done for all the tables you have touched in your Extension .. new and modified!

Now, one point of concern: This recref is NOT based on the original table, which you might have expected. So you will not be able to do something like DestinationRecRef := SourceRecRef , or DestinationRecRef.GET(SourceRecRef) … or anything in that sort. There is only the long way (as far as I know) .. the only thing you can do, is looping the fields, and transfer the data field-by-field back to where it belonged. You have to manage lost data, lost fields, conversions, … everything in code.

So, imagine, if you need to foresee upgrade code for every field .. you might want to do this as generic as possible – else, at some point in the future, you WILL forget to add upgrade code for a new field you added in a new version of the Extension .. .

Let me show you one way to do this generically .. not claiming it’s the only way, or the best way .. It’s just ‘a’ way 😉

I will share the codeunit at the end of this blogpost. But let’s first look at the main function:

And this explains it all already :-). I have two functions and a few assumptions (I know .. they probably are mother of all f***ps.. but still ..).

When you design tables in an extension, you will either change a default table, of you will add new tables. So it’s these situations that are handled in the two functions. On top of that, I need to do a few assumptions:

  • The new fields in the modified tables, are in a specified range. In this case: 50000..99999. In this case, other fields will be skipped. Beware! The code is looping all the fields in default tables
  • For the new table, I need to loop ALL fields. In this case, I assume the new tables are in a specific number range. In this case, once again, 50000..99999.

Makes sense, but still, it’s assumptions, and you should be aware!

But taking this in account, it’s possible to just loop the Fields-table / Object table, and you’re good to go. With only one remark: don’t loop the Object table (that table isn’t aware of the Extension-objects), but loop the AllObj-table, like you see in the code below.

That’s about it. The rest is quite straight forward. Here is the codeunit – enjoy!

 

One big disclaimer though .. I did NOT test this code thoroughly. But I did test it somewhat ;-). If there are issues, you’re always welcome to comment, and I’ll try to look at it!

3.83 avg. rating (79% score) - 6 votes

Permanent link to this article: http://www.waldo.be/2016/01/08/nav-extensions-generic-code-to-migrate-data-when-upgrading-extension/

4 comments

3 pings

Skip to comment form

  1. James Crowter

    Any thoughts on performance of this technique Waldo? When your adding fields to some of tables with more records like Item ledger entries or sales invoice lines as part of your extensions, in a few years you might well have hundreds of tenants with millions of records, how long is it going to take to upgrade your extension?

    1. waldo

      Absolutely no thoughts on that, James.. . I can only assume that it slows down quite a lot in that case.. .
      But I will test 😉

  2. Ben

    I think this:
    DestinationRecRef.OPEN(DATABASE::Table69601,FALSE);
    should be this:
    DestinationRecRef.OPEN(“Object ID”,FALSE);

    1. waldo

      You are totally correct, my apologies;

      but .. please open the most recent post about it here (I refer to it in the first line of this blogpost):
      http://www.waldo.be/2016/01/20/nav-extensions-updated-generic-data-migration-options/

  1. NAV Extensions – Updated Generic Data Migration Options » waldo's blog

    […] was so proud with my previous blogpost as I was able to solve a somewhat complicated problem generically. And now there appears to be a […]

  2. NAV Extensions – Updated Generic Data Migration Options - Microsoft Dynamics NAV Community

    […] was so proud with my previous blogpost as I was able to solve a somewhat complicated problem generically. And now there appears to be a […]

Leave a Reply

%d bloggers like this: