Files
lmxopcua/docs/GalaxyRepository.md

6.2 KiB

Galaxy Repository

GalaxyRepositoryService reads the Galaxy object hierarchy and attribute metadata from the System Platform Galaxy Repository SQL Server database. This data drives the construction of the OPC UA address space.

Connection Configuration

GalaxyRepositoryConfiguration controls database access:

Property Default Description
ConnectionString Server=localhost;Database=ZB;Integrated Security=true; SQL Server connection using Windows Authentication
ChangeDetectionIntervalSeconds 30 Polling frequency for deploy change detection
CommandTimeoutSeconds 30 SQL command timeout for all queries
ExtendedAttributes false When true, loads primitive-level attributes in addition to dynamic attributes

The connection uses Windows Authentication because the Galaxy Repository database is local to the System Platform node and secured through domain credentials.

SQL Queries

All queries are embedded as const string fields in GalaxyRepositoryService. No dynamic SQL is used.

Hierarchy query

Returns deployed Galaxy objects with their parent relationships, browse names, and template derivation chains:

  • Joins gobject to template_definition to filter by relevant category_id values (1, 3, 4, 10, 11, 13, 17, 24, 26)
  • Uses contained_name as the browse name, falling back to tag_name when contained_name is null or empty
  • Resolves the parent using contained_by_gobject_id when non-zero, otherwise falls back to area_gobject_id
  • Marks objects with category_id = 13 as areas
  • Filters to is_template = 0 (instances only, not templates)
  • Filters to deployed_package_id <> 0 (deployed objects only)
  • Returns a template_chain column built by a recursive CTE that walks gobject.derived_from_gobject_id from each instance through its immediate template and ancestor templates (depth guard < 10). Template names are ordered by depth and joined with | via STUFF(... FOR XML PATH('')). Example: TestMachine_001 returns $TestMachine|$gMachine|$gUserDefined|$UserDefined. The C# repository reader splits the column on |, trims, and populates GalaxyObjectInfo.TemplateChain, which is consumed by AlarmObjectFilter for template-based alarm filtering. See Alarm Tracking.

Attributes query (standard)

Returns user-defined dynamic attributes for deployed objects:

  • Uses a recursive CTE (deployed_package_chain) to walk the package inheritance chain from deployed_package_id through derived_from_package_id, limited to 10 levels
  • Joins dynamic_attribute on each package in the chain to collect inherited attributes
  • Uses ROW_NUMBER() OVER (PARTITION BY gobject_id, attribute_name ORDER BY depth) to pick the most-derived definition when an attribute is overridden at multiple levels
  • Builds full_tag_reference as tag_name.attribute_name with [] appended for arrays
  • Extracts array_dimension from the binary mx_value column (bytes 13-16, little-endian int32)
  • Detects historized attributes by checking for a HistoryExtension primitive instance
  • Detects alarm attributes by checking for an AlarmExtension primitive instance
  • Excludes internal attributes (names starting with _) and .Description suffixes
  • Filters by mx_attribute_category to include only user-relevant categories

Attributes query (extended)

When ExtendedAttributes = true, a more comprehensive query runs that unions two sources:

  1. Primitive attributes -- Joins through primitive_instance and attribute_definition to include system-level attributes from primitive components. Each attribute carries its primitive_name so the address space can group them under their parent variable.
  2. Dynamic attributes -- The same CTE-based query as the standard path, with an empty primitive_name.

The full_tag_reference for primitive attributes follows the pattern tag_name.primitive_name.attribute_name (e.g., TestMachine_001.AlarmAttr.InAlarm).

Change detection query

A single-column query: SELECT time_of_last_deploy FROM galaxy. The galaxy table contains one row with the timestamp of the most recent deployment.

Why deployed_package_id Instead of checked_in_package_id

The Galaxy maintains two package references for each object:

  • checked_in_package_id -- The latest saved version, which may include undeployed configuration changes
  • deployed_package_id -- The version currently running on the target platform

The queries filter on deployed_package_id <> 0 because the OPC UA server must mirror what is actually running in the Galaxy runtime. Using checked_in_package_id would expose attributes and objects that exist in the IDE but have not been deployed, causing mismatches between the OPC UA address space and the MXAccess runtime.

Change Detection Polling

ChangeDetectionService runs a background polling loop that calls GetLastDeployTimeAsync at the configured interval. It compares the returned timestamp against the last known value:

  • On the first poll (no previous state), the timestamp is recorded and OnGalaxyChanged fires unconditionally
  • On subsequent polls, OnGalaxyChanged fires only when time_of_last_deploy differs from the cached value

When the event fires, the host service queries fresh hierarchy and attribute data from the repository and calls LmxNodeManager.RebuildAddressSpace (which delegates to incremental SyncAddressSpace).

The polling approach is used because the Galaxy Repository database does not provide change notifications. The galaxy.time_of_last_deploy column updates only on completed deployments, so the polling interval controls how quickly the OPC UA address space reflects Galaxy changes.

TestConnection

TestConnectionAsync runs SELECT 1 against the configured database. This is used at service startup to verify connectivity before attempting the full hierarchy query.

Key source files

  • src/ZB.MOM.WW.LmxOpcUa.Host/GalaxyRepository/GalaxyRepositoryService.cs -- SQL queries and data access
  • src/ZB.MOM.WW.LmxOpcUa.Host/GalaxyRepository/ChangeDetectionService.cs -- Deploy timestamp polling loop
  • src/ZB.MOM.WW.LmxOpcUa.Host/Configuration/GalaxyRepositoryConfiguration.cs -- Connection and polling settings