The end of life for Umbraco 7 is getting near (September 2023), and with Umbraco 11 already being out for several months this is the perfect time to migrate your Umbraco solution! Today we will be taking a look at an issue that I've been running into during one of the recent Umbraco migrations from Umbraco 7 to Umbraco 10+!
The Problem
During the migration, we kept running into some difficult to replicate behavior involving the Umbraco NuCache and the fetching of specific properties of published content. Depending on the different stages in the lifecycle of our application, we would fetch the same Umbraco Content item, but were getting different values for the same properties. We were able to narrow it down to said properties being Nested Content items, but that's when we ran into a brick wall... until we started taking a better look at the properties on a Database level, and compared them to other Nested Content properties of which we were actually getting the data from!
In summary, what has happened in the past (in Umbraco 7) was that a bunch of Content nodes have been copied/duplicated, and some of the values of these properties have been modified. Nothing out of the ordinary about that, until we've noticed that the data of the various Nested Content properties on those Content Nodes have also been duplicated... including the (supposed to be) unique Keys! The various values within the Nested Content properties have been modified later on, but the keys themselves have stayed the same, as these are inaccessible to the Content editor.
Now, in Umbraco 7 these keys supposedly served no real purpose yet... while in Umbraco 8+ they are used as the unique identifier in the NuCache (See where I'm going with this?). So, what turned out what was happening, was that depending on where in the lifecycle of our application we would request a specific item, if multiple nested content items with the same key have been requested, depending on which item was stored in the NuCache last would be the one that we were getting back! 🤯
The Solution
Now that we've figured out what the problem was, in theory the solution would be quite simple; "Change the duplicate keys to be new unique keys, and we're done!"... turns out that would be a little bit more complicated to resolve, but manageable in the end!
To get some insights into the data that we're working with, we'll be using the following SQL Query, that will give us all the UmbracoPropertyData rows that are a single layer deep Nested Content, joined together with the various ContentVersionIds of that UmbracoPropertyData, and the actual NodeID & NodeName to correspond to that Content.
To change all the various keys to a set new unique GUIDs, we will be using an Umbraco Migration to be able to perform some more complex logic on our Database queries. Be sure to check out the following blog to learn more about how to create & run Migrations in Umbraco 10+: https://cornehoskam.com/posts/how-to-create-run-migrations-umbraco-v10
We are started off executing the query above and parsing the data to a custom DTO model to map the properties, ending up with a list of all the Nested Content properties of our entire Umbraco application. The next step is to modify the keys, but to do so there are a couple of rules we need to follow. First off, we will need to group our all nested content properties by their nodeIds, so that we can ForEach over them.
After that, we'll need to create a sub-group within those Nodes, where we group all properties together that currently have the same Nested Content Key. The reason for doing that, is so that we are able to change the keys of the various versions of the same property within the same node to a unique set of keys, but have the keys be the same across the different past versions.
Once that is done, we can generate a new GUID. For each property within the final ForEach group we perform a Regex Replace to exchange the old key with the new key, and then execute a SQL query to update our Database record!
Lastly we need to make sure to rebuild the Database Cache & Memory Cache across our servers so that the NuCache reflects our newly updated property data, and we're done! We've now successfully generated a new set of unique GUIDs for each and every nested content property in our application.
An example implementation of the scenario described above could be as follows:
DISCLAIMER: The example shown above should only be used as an example, and should be thoroughly tested before executed on your own codebase & database. The queries executed in said example are destructive and could negatively impact your application & corrupt data all together if done incorrectly. Always ensure you have back-ups!
Summary
Umbraco Nested Content Data & NuCache can cause some tricky and difficult to debug situations, especially during a migration to a later version of Umbraco. After some investigating a scenario involving duplicate nested content GUIDs turned out to be the cause of most (if not all) our Content issues. By replacing the existing keys for a specific property & nodeId to a new set of unique keys during a custom Migration, we have managed to resolve our issues and have our application running smoothly again! 🔥
If you have any further questions, feel free to contact me over at my socials available at the Contact page, and I'd love to hear about either your success stories, or further troubles to help improve this blog! 😄