top of page

How I rename a published model safely

  • Jul 1
  • 4 min read

Part two was the safe half: descriptions and synonyms, nothing structural moves. Renaming is the harder half.


Whenever we're working with a published semantic model that's in use, there are multiple reports created on top of it. That's when renaming an attribute becomes a worry, because you don't always know where it might have an impact. Quite a few times we'll avoid the change altogether and do the rename inside the visuals instead. Synonyms help Copilot cope with the names, but they don't change them. And sometimes you do want the name changed. I wanted to find out if it could be done safely.


What a rename touches


The reason it's a worry is that a name lives in far more places than the one you're looking at. Change a single column and you touch the declaration, every measure and calculated column that references it, the security role filters, the relationships, the sort-by and hierarchy settings, and the linguistic metadata behind Q&A. And that's only the model.


The reports are separate items, and that's where most of the breakage is. I used to think a report was safe from this, because it connects to the dataset by "connection". It isn't. The connection only points at the dataset. Every visual stores its fields as structured references, table and property, and the moment the property no longer exists, the visual goes blank. Report-level measures are the part I didn't expect: reports can define their own measures, living inside the report rather than the model, and those measures contain DAX that points straight at model columns. Rename a column and that DAX breaks too, inside a file almost nobody opens. That's the whole reason renaming gets avoided, it breaks things in places you can't see from one screen.


What the tool does


So before it changes anything, it produces an impact report: every reference a rename would touch, in the model and in the reports, each with its before and its after.


python rename_plan.py --workspace <ws> --dataset <ds> \
    --table "dim_date=Date" \
    --measure "fact_trade_total_monthly.Total Exports (GBP bn)=Exports" \
    --discover-reports


The flag I find most useful is --discover-reports. Reports are separate items, so the tool reads each report's definition, finds the dataset id buried in its connection string, and pulls in only the reports actually bound to this model. I didn't give it any paths. It found the connected report on its own: 43 reference sites, eleven in the model and thirty-two across seven visuals in one report.


The rename impact report: an overview of everything renaming dim_date and the Total Exports measure would touch, then every reference with its before and after. 43 sites in all, 11 in the model and 32 across 7 visuals in one report.


It's careful about what it won't touch, too. The link to the warehouse, the source column mappings and the Power Query expressions, is left alone. The logical name changes; the refresh doesn't notice. Then it suggests names, because naming is a judgement call. It strips the dim_ and fact_ prefixes, title-cases, expands the acronyms it knows (hmrc to HMRC, iso2 to ISO-2), and writes the proposals to a file I edit before anything runs. I approve the list; it doesn't decide for me.


All of this happens on a staging copy, with a backup taken first, so the live model is untouched. But staging only tells me the model loads, not that the report still works. So for every visual it reads the fields that visual uses and runs a small DAX query against the renamed staging model to check each one resolves, and report-level measures get checked by running their actual expression.


That validation caught two bugs in my own code. The first: I'd rewritten the field references in the visuals but not the DAX inside the report-level measures. The validation lit up red on _Verdict and _Period Label, measures pointing at dim_date[date] and [Trade Balance (GBP bn)]. Without that catch, the rename would have looked like a clean success and quietly broken four measures. The second: one of the suggested names was dim_date to Date. Date is a DAX function, so Date[Date] is a syntax error. The fix was to quote table names that clash with reserved words, 'Date'[Date]. The validation found it by running the query and getting the error back from the engine. A plain find-and-replace would have made both changes and reported success, with the report quietly broken.


It isn't finished, and there's plenty it doesn't handle. Report discovery only sees the same workspace, so reports in other workspaces sharing the dataset need a different approach, and the tool says so rather than missing them silently. External consumers, Excel pivots, embedded tiles, paginated reports, composite models, no tool can see those, and the impact report flags that every time. And an unqualified [name] in DAX could be a measure or a same-named column in row context, so those get marked for a human to look at rather than guessed. It won't make the naming decisions for you; it takes out the mechanical risk so you can focus on those.


How it went on a real model


I renamed all 137 attributes on a real model, twenty tables and a hundred and seventeen columns, rewrote the connected report including its report-level measures, checked every visual with live DAX, and promoted the model and the report to production together, with a backup taken first. The live report came back green, every binding resolving against the new names, and the refresh didn't notice. fact_trade_total_monthly became Trade (Total, Monthly), and country_code_iso2 became Country Code (ISO-2).


The safe rename workflow is in the open-source toolkit from part one: the impact report, the suggested names, the apply-to-staging, the report rewrite, and the DAX checks. No AI, running in your own tenant. The full production publish, the part that renames the live model and all its reports together with rollback, is the part I do as a service. If there's a model whose names you've been avoiding for years, reach out and I'll help.

Comments


bottom of page