Table of Contents

Metric View Object Model

Note

The Semantic Bridge as released in 3.25.0 is an MVP feature. It has limitations as documented below, and the API and feature surface area are subject to change. The object model here conspicuously lacks many affordances available in the TOMWrapper which users may be familiar with from C# scripts that manipulate a Tabular model. As noted in the limitations of the Semantic Bridge, we currently only support Metric View v0.1 metadata.

The Semantic Bridge includes an object model representing a Databricks Metric View. This allows you to work with Metric Views programmatically through C# scripts, similar to how you work with a Tabular model through the TOMWrapper.

Other than the import GUI, all access to and interaction with a Metric View is through C# scripts. All content in this document is referring to C# code that you will use in a C# script.

Loading and accessing the Metric View

You can load a Metric view with SemanticBridge.MetricView.Load or SemanticBridge.MetricView.Deserialize. This stores the deserialized Metric View as SemanticBridge.MetricView.Model. This property returns a View object, which is the root of the Metric View object graph.

// Load a Metric View from disk
SemanticBridge.MetricView.Load("C:/path/to/metricview.yaml");

// Access the loaded View
var view = SemanticBridge.MetricView.Model;
Output($"Metric View version: {view.Version}\r\nSource: {view.Source}");

Similar to a Tabular model and dissimilar to most other objects you may be used to in a C# script, the Metric View is persistent across multiple script executions. This means that you can load a Metric View once, and reference it from subsequent script executions without re-loading it every time. There is only ever a single Metric View loaded, and it is available in all scripts as SemanticBridge.MetricView.Model as mentioned above. This behavior is similar to the Tabular model in C# scripts, which is always available simply as Model.

Domain objects

The object model consists of four main types that correspond to the structure of a Metric View YAML file: We do not repeat the entire specification here, so we encourage you to reference the Databricks Metric View documentation.

API Reference Description
View The root object representing the entire Metric View
Join A join definition connecting a dimension table to the fact
Dimension A field definition (column) in the Metric View
Measure An aggregation definition representing business logic
Note

In the object model, we follow C# naming conventions, and so use PascalCase for all type and property names in the object model. The Metric View YAML specification follows a naming convention of snake_case. In general, we focus on the C# object model that is a component of the Semantic Bridge. Other than changing the case, we do not change any naming convention from the YAML.

View

The View object is the root of the Metric View and contains:

  • Version: The Metric View specification version (e.g., "0.1")
  • Source: The source data for the fact table (e.g., "catalog.schema.table")
  • Filter: Optional SQL boolean expression that applies to all queries
  • Joins: Collection of join definitions
  • Dimensions: Collection of dimension (field) definitions
  • Measures: Collection of measure definitions
var sb = new System.Text.StringBuilder();
var view = SemanticBridge.MetricView.Model;

sb.AppendLine($"Version: {view.Version}");
sb.AppendLine($"Source: {view.Source}");
sb.AppendLine($"Filter: {view.Filter ?? "(none)"}");
sb.AppendLine($"Joins: {view.Joins?.Count ?? 0}");
sb.AppendLine($"Dimensions: {view.Dimensions?.Count ?? 0}");
sb.AppendLine($"Measures: {view.Measures?.Count ?? 0}");

Output(sb.ToString());

View translation and validation

The View.Source property becomes the fact table in the Tabular model, named 'Fact'. If the Source is a 3-part table or view reference, it is translated to an M partition that accesses the SQL object by name. If the Source is not a 3-part table or view reference, it is translated to an M partition with an embedded SQL query, with the entirety of the Source string as the SQL query. The Filter property is ignored for purposes of translation.

For purposes of evaluating validation rules, the View is checked first, then each collection is validated in order: Joins, then Dimensions, then Measures. Validation of the fact table, Source is done in a validation rule for the View object.

Join

A Join represents a dimension table that is joined to the fact table:

  • Name: Name of the joined table (used as an alias)
  • Source: Source table or query for the join (e.g., "catalog.schema.dimension_table")
  • On: Optional SQL boolean expression for the join condition
  • Using: Optional list of column names for the join (alternative to On)
  • Joins: Child joins (for snowflake schemas)
var sb = new System.Text.StringBuilder();
var view = SemanticBridge.MetricView.Model;

foreach (var join in view.Joins ?? [])
{
    sb.AppendLine($"Join: {join.Name}");
    sb.AppendLine($"  Source: {join.Source}");
    if (!string.IsNullOrEmpty(join.On))
        sb.AppendLine($"  On: {join.On}");
    if (join.Using != null && join.Using.Count > 0)
        sb.AppendLine($"  Using: {string.Join(", ", join.Using)}");
}

Output(sb.ToString());

Join translation and validation

Nested Joins are not supported, i.e., only a strict star schema can be translated. Only On joins with a single-field equijoin are supported for translation. Joins each become a Tabular table, with an M partition defined according to the same rules as for the View.Source property.

Joins are validated in the order they appear in the Metric View definition.

Dimension

A Dimension represents a field (column) in the Metric View:

  • Name: The display name for the dimension
  • Expr: The SQL expression defining the dimension (either a column reference or a SQL expression)
var sb = new System.Text.StringBuilder();
var view = SemanticBridge.MetricView.Model;

foreach (var dim in view.Dimensions ?? [])
{
    sb.AppendLine($"Dimension: {dim.Name}");
    sb.AppendLine($"  Expression: {dim.Expr}");
}

Output(sb.ToString());

Dimension translation and validation

Each Dimension becomes a column in the Tabular model. If the Expr is an unqualified field reference, it is added to the fact table. If the Expr is a qualified reference (e.g., table.field), then it is added to the table created for the Join with the same name as the table-part of the qualified reference; if the table-part is source, it is added to the fact table. In both the qualified and unqualified field reference cases, the field is added as a TOMWrapper.DataColumn. If the Expr is a SQL expression, then it is added as TOMWrapper.CalculatedColumn. When the Expr is a SQL expression, we attempt to extract all field references; if all field references share the same table-part, then we add it to the table created for that Join, otherwise we add it to the fact table. We do not translate SQL expressions for Dimension.Expr properties; the SQL expression is included as a comment in the DAX expression for the CalculatedColumn. It is up to the user to translate these expressions. We attempt to identify all field references in the SQL expression and add those to the Tabular model as DataColumns if they do not already exist as a Metric View Dimension.

Some examples:

Expr Translated as type Added to table Note
field1 DataColumn 'Fact' unqualified field references are equivalent to those qualified with source
source.field2 DataColumn 'Fact' source is a reference to the View.Source property, aka the fact table
dimCustomer.key DataColumn 'dimCustomer' there must be a Join whose Name property is dimCustomer
CONCAT(dimCustomer.FirstName, dimCustomer.LastName) CalculatedColumn 'dimCustomer' all table-parts of the qualified name refer to the same name
CONCAT(dimGeo.Country, dimCustomer.Address) CalculatedColumn 'Fact' there are multiple distinct table-parts

Dimensions are validated in the order they appear in the Metric View definition.

Measure

A Measure represents a named aggregation with business logic:

  • Name: The display name for the measure
  • Expr: The SQL aggregate expression defining the measure
var sb = new System.Text.StringBuilder();
var view = SemanticBridge.MetricView.Model;

foreach (var measure in view.Measures ?? [])
{
    sb.AppendLine($"Measure: {measure.Name}");
    sb.AppendLine($"  Expression: {measure.Expr}");
}

Output(sb.ToString());

Measure translation and validation

All measures are added to the fact table. Simple aggregations are translated into DAX expressions. A simple aggregation is a single aggregation of a single field (e.g. SUM(table.field)). Supported aggregations are sum, count, distinct count, max, min, and average. Other expressions are passed through as a comment in the DAX expression of the Tabular measure. We attempt to identify all field references in the SQL expression and add those to the Tabular model as DataColumns if they do not already exist as a Metric View Dimension.

Warning

SQL and DAX are different languages with different semantics. It is possible that an automatically translated measure does not express the same computation in both Databricks Metric Views and Tabular models. It is up to the user to verify all code works as expected.

Measures are validated in the order they appear in the Metric View definition.

Using directives

When working with the Metric View object model in C# scripts, you may need to add a using directive to avoid naming conflicts with similarly-named types in the Tabular Object Model. We recommend aliasing the namespace:

// Alias to avoid conflicts with TOM types like Measure
using MetricView = TabularEditor.SemanticBridge.Platforms.Databricks.MetricView;

SemanticBridge.MetricView.Load("C:/path/to/metricview.yaml");
var view = SemanticBridge.MetricView.Model;

// Now you can reference types explicitly
foreach (MetricView.Dimension dim in view.Dimensions ?? [])
{
    // ...
}

Complete example

Here is a complete script that loads a Metric View and outputs a summary of its contents:

using MetricView = TabularEditor.SemanticBridge.Platforms.Databricks.MetricView;

// Load the Metric View
SemanticBridge.MetricView.Load("C:/path/to/metricview.yaml");
var sb = new System.Text.StringBuilder();
var view = SemanticBridge.MetricView.Model;

// sb.AppendLine summary
sb.AppendLine("=== Metric View Summary ===");
sb.AppendLine($"Version: {view.Version}");
sb.AppendLine($"Source: {view.Source}");

if (view.Joins != null && view.Joins.Count > 0)
{
    sb.AppendLine($"\nJoins ({view.Joins.Count}):");
    foreach (var join in view.Joins)
    {
        sb.AppendLine($"  - {join.Name} -> {join.Source}");
    }
}

if (view.Dimensions != null && view.Dimensions.Count > 0)
{
    sb.AppendLine($"\nDimensions ({view.Dimensions.Count}):");
    foreach (var dim in view.Dimensions)
    {
        sb.AppendLine($"  - {dim.Name}: {dim.Expr}");
    }
}

if (view.Measures != null && view.Measures.Count > 0)
{
    sb.AppendLine($"\nMeasures ({view.Measures.Count}):");
    foreach (var measure in view.Measures)
    {
        sb.AppendLine($"  - {measure.Name}: {measure.Expr}");
    }
}

Output(sb.ToString());

References