Skip to main content

Merging Metadata

BimlFlex provides stored procedures for merging project metadata from one version (or customer) into another. This is useful when consolidating work from parallel development branches, promoting metadata between environments, or combining metadata from multiple teams into a single version.

The merge workflow is a two-step process:

  1. Preview — inspect what will change, identify conflicts
  2. Execute — apply the merge, providing conflict resolutions where needed

Prerequisites

  • Direct access to the BimlFlex metadata database (SQL Server Management Studio, Azure Data Studio, or similar)
  • Knowledge of the source and target Customer UID and Version Name values
  • The source version must already exist; the target version will be created automatically if it does not exist
tip

You can find Customer UIDs and Version Names by querying the [app].[Versions] table:

SELECT [CustomerUID], [Name] AS VersionName
FROM [app].[Versions]
ORDER BY [CustomerUID], [Name]

Entity Scope

A project merge covers five entity types, processed in dependency order:

OrderEntity TypeScoped Name FormatExample
1BatchBatchNameLOAD_BDV
2ConnectionConnectionNameAWLT_SRC
3ProjectProjectNameEXT_AWLT_SRC
4ObjectConnection.Schema.ObjectNameAWLT_SRC.SalesLT.Customer
5ColumnConnection.Schema.Object.ColumnNameAWLT_SRC.SalesLT.Customer.CustomerID

Only entities that belong to the specified project (and their dependencies) are included in the merge.

Step 1 — Preview the Merge

Use merge.PreviewProject to generate a read-only conflict report without making any changes to the target version.

Syntax

EXEC [merge].[PreviewProject]
@SourceCustomerUID = '<source-customer-uid>'
,@SourceVersionName = '<source-version-name>'
,@TargetCustomerUID = '<target-customer-uid>'
,@TargetVersionName = '<target-version-name>'
,@ProjectName = '<project-name>'

Parameters

ParameterTypeDescription
@SourceCustomerUIDNVARCHAR(40)The Customer UID of the source version
@SourceVersionNameNVARCHAR(256)The name of the source version to merge from
@TargetCustomerUIDNVARCHAR(40)The Customer UID of the target version
@TargetVersionNameNVARCHAR(256)The name of the target version to merge into
@ProjectNameNVARCHAR(256)The project whose metadata will be merged

Example

EXEC [merge].[PreviewProject]
@SourceCustomerUID = 'A0E1B2C3-D4F5-6789-ABCD-EF0123456789'
,@SourceVersionName = 'Sprint 24'
,@TargetCustomerUID = 'A0E1B2C3-D4F5-6789-ABCD-EF0123456789'
,@TargetVersionName = 'Sprint 25'
,@ProjectName = 'EXT_AWLT_SRC'

Understanding the Results

The preview returns one row per entity with the following columns:

ColumnDescription
ConflictIdSequential number identifying each row. Use this value to reference specific conflicts when providing overrides.
EntityTypeThe type of entity: Batch, Connection, Project, Object, or Column.
ScopedNameThe fully-qualified name of the entity (format varies by entity type — see table above).
SourceUIDThe unique identifier of the entity in the source version.
TargetUIDThe unique identifier of the matching entity in the target version, or NULL if no match was found.
MatchTypeHow the entity was matched: ScopedName (matched by name), ClonedFromUID (matched via clone lineage), or NULL (no match — new entity).
HasConflict1 if the source and target entities differ in one or more business columns; 0 otherwise.
DiffColumnsA comma-separated list of column names that differ between source and target. NULL if there is no conflict.
MergeActionThe action that will be taken: Add (new entity), Conflict (requires resolution), or Unchanged (identical in both versions).

Interpreting Merge Actions

  • Add — The entity exists in the source but has no match in the target. It will be added during execution.
  • Unchanged — The entity exists in both versions and all business columns are identical. No action needed.
  • Conflict — The entity exists in both versions but one or more business columns differ. You must provide a conflict resolution before executing the merge.

Example Output

ConflictIdEntityTypeScopedNameMatchTypeHasConflictMergeAction
1BatchLOAD_BDVScopedName0Unchanged
2ConnectionAWLT_SRCScopedName1Conflict
3ConnectionBDV_STGNULL0Add
4ProjectEXT_AWLT_SRCScopedName0Unchanged
5ObjectAWLT_SRC.SalesLT.CustomerScopedName1Conflict

In this example:

  • ConflictId 2 (AWLT_SRC connection) has a conflict — check the DiffColumns value to see which properties differ
  • ConflictId 3 (BDV_STG connection) is new and will be added automatically
  • ConflictId 5 (Customer object) has a conflict that needs to be resolved

Step 2 — Execute the Merge

After reviewing the preview, use merge.ExecuteProject to apply the merge. If the preview identified any conflicts, you must provide resolutions via the @ConflictOverrides parameter.

Syntax

EXEC [merge].[ExecuteProject]
@SourceCustomerUID = '<source-customer-uid>'
,@SourceVersionName = '<source-version-name>'
,@TargetCustomerUID = '<target-customer-uid>'
,@TargetVersionName = '<target-version-name>'
,@ProjectName = '<project-name>'
,@ConflictOverrides = '<json-overrides>'
,@UserName = '<user-name>'

Parameters

ParameterTypeRequiredDescription
@SourceCustomerUIDNVARCHAR(40)YesThe Customer UID of the source version
@SourceVersionNameNVARCHAR(256)YesThe name of the source version to merge from
@TargetCustomerUIDNVARCHAR(40)NoThe Customer UID of the target version. Defaults to the source customer if omitted.
@TargetVersionNameNVARCHAR(256)YesThe name of the target version to merge into. Created automatically if it does not exist.
@ProjectNameNVARCHAR(256)YesThe project whose metadata will be merged
@ConflictOverridesNVARCHAR(MAX)NoA JSON document specifying how to resolve conflicts (see below). Required if the preview shows any Conflict rows.
@UserNameNVARCHAR(256)NoThe user name recorded as the author of the merge. Defaults to the current SQL login.

Conflict Resolution

Each conflict must be resolved as either:

  • take-incoming — replace the target entity with the source version (accept the incoming change)
  • take-target — keep the target entity as-is (reject the incoming change)

The @ConflictOverrides parameter accepts two JSON formats. You can use whichever is more convenient.

Format 1: By Entity Type and Scoped Name

Reference conflicts using the entity type and scoped name from the preview results:

{
"Connection": {
"AWLT_SRC": "take-incoming"
},
"Object": {
"AWLT_SRC.SalesLT.Customer": "take-target"
}
}

Format 2: By Conflict ID

Reference conflicts using the ConflictId number from the preview results:

{
"2": "take-incoming",
"5": "take-target"
}
caution

Conflict IDs are assigned dynamically and may change if metadata is modified between preview and execution. If you are working in an environment where other users may be making concurrent changes, prefer Format 1 (entity type + scoped name) for more stable references.

Example — No Conflicts

When the preview shows only Add and Unchanged actions, no overrides are needed:

EXEC [merge].[ExecuteProject]
@SourceCustomerUID = 'A0E1B2C3-D4F5-6789-ABCD-EF0123456789'
,@SourceVersionName = 'Sprint 24'
,@TargetCustomerUID = 'A0E1B2C3-D4F5-6789-ABCD-EF0123456789'
,@TargetVersionName = 'Sprint 25'
,@ProjectName = 'EXT_AWLT_SRC'

Example — With Conflict Resolutions

Using the preview output from Step 1, resolve both conflicts:

EXEC [merge].[ExecuteProject]
@SourceCustomerUID = 'A0E1B2C3-D4F5-6789-ABCD-EF0123456789'
,@SourceVersionName = 'Sprint 24'
,@TargetCustomerUID = 'A0E1B2C3-D4F5-6789-ABCD-EF0123456789'
,@TargetVersionName = 'Sprint 25'
,@ProjectName = 'EXT_AWLT_SRC'
,@ConflictOverrides = '{
"Connection": { "AWLT_SRC": "take-incoming" },
"Object": { "AWLT_SRC.SalesLT.Customer": "take-target" }
}'
,@UserName = 'kim@contoso.com'

Understanding the Results

The execution returns a summary with one row per entity:

ColumnDescription
ConflictIdSequential row identifier
EntityTypeThe entity type
ScopedNameThe fully-qualified entity name
MergeResultThe outcome: Added, Updated (take-incoming), Kept (take-target), or Unchanged

Unresolved Conflicts

If any conflicts remain unresolved, the merge is blocked — no changes are made. The procedure returns the full conflict report with unresolved rows marked as Conflict (UNRESOLVED) and raises an error:

Merge blocked: unresolved conflicts exist. Provide @ConflictOverrides for all conflicts.

Review the unresolved conflicts and re-execute with the appropriate overrides.

Full Workflow Example

The following example walks through a complete merge from Sprint 24 to Sprint 25 within the same customer.

1. Preview

-- Step 1: See what will happen
EXEC [merge].[PreviewProject]
@SourceCustomerUID = 'A0E1B2C3-D4F5-6789-ABCD-EF0123456789'
,@SourceVersionName = 'Sprint 24'
,@TargetCustomerUID = 'A0E1B2C3-D4F5-6789-ABCD-EF0123456789'
,@TargetVersionName = 'Sprint 25'
,@ProjectName = 'EXT_AWLT_SRC'

Review the results. Note any rows where MergeAction = 'Conflict' and check DiffColumns to understand what differs.

2. Decide Resolutions

For each conflict, decide whether to accept the incoming (source) value or keep the current target value. Use the DiffColumns output to guide your decision.

3. Execute

-- Step 2: Apply the merge with resolutions
EXEC [merge].[ExecuteProject]
@SourceCustomerUID = 'A0E1B2C3-D4F5-6789-ABCD-EF0123456789'
,@SourceVersionName = 'Sprint 24'
,@TargetCustomerUID = 'A0E1B2C3-D4F5-6789-ABCD-EF0123456789'
,@TargetVersionName = 'Sprint 25'
,@ProjectName = 'EXT_AWLT_SRC'
,@ConflictOverrides = '{"2": "take-incoming", "5": "take-target"}'
,@UserName = 'kim@contoso.com'

4. Verify

Review the MergeResult column in the output to confirm all entities were handled as expected.

Cross-Customer Merges

The merge procedures support merging metadata between different customers by specifying different values for @SourceCustomerUID and @TargetCustomerUID. This is useful when:

  • Consolidating metadata from a development customer into a production customer
  • Combining work from isolated teams that used separate customers
  • Migrating a project from one BimlFlex deployment to another (same database)
note

When merging across customers, entity matching relies on scoped names and clone lineage (ClonedFromUID). Entities that were independently created in both customers with the same name will be matched by name and may show as conflicts if their properties differ.

Tips and Best Practices

  • Always preview before executing. The preview is read-only and shows you exactly what will happen.
  • Snapshot your target version before executing a merge, so you can roll back if needed.
  • Use scoped-name overrides (Format 1) when working in environments with concurrent metadata changes, as ConflictIds can shift.
  • Review DiffColumns carefully before choosing a resolution. The column-level detail helps you understand the impact of each conflict.
  • Coordinate with your team. If multiple developers are working on the same version, ensure no one is actively editing the target version during a merge.
  • The merge operates within a single transaction. If any step fails, all changes are rolled back automatically.