Note: This release is in preview. Features described here don’t become generally available until the latest general availability date that Salesforce announces for this release. Before then, and where features are noted as beta, pilot, or developer preview, we can’t guarantee general availability within any particular time frame or at all. Make your purchase decisions only on the basis of generally available products and features.
Relationships
Here’s a comprehensive overview of relationships, their syntax, purpose, and key features, particularly using examples relevant to the Generator Set model.
Definition and Syntax of Relationships
Relationships define the one-to-many connections between a parent type (such as a bundle) and its component types (children).
- Keyword: The keyword used is relation.
- Syntax: A basic relationship declaration includes the relation name, the target type,
and cardinality
bounds.
1relation <relation name> : <Target Type>[min..max] { /* Optional content */ } - Purpose: Relationships represent the product structure in a bundle. For example, the root product (GeneratorSet) has relationships with its components (MainAlternators, TemperatureSensors).
Set Maximum Relationship Size
The maxRelationSize property is the maximum cardinality for a single relationship in the constraint model. It controls how many instances of a child component can exist under one parent through the relationship. The maximum value for maxRelationSize is 1073741824. The default value is 9999.
Use maxRelationSize to set a limit based on the number of instances you need for your business purposes. For example, if the most a customer can order of a child component is 200,000, set maxRelationSize to 200,000. An overly high cardinality limit increases the risk of unbound variables that cause the constraint engine to backtrack through the entire range to resolve a conflict. Use maxRelationSize with the property.
1property maxRelationSize = 100000;
2 type Quote {
3
4 relation items : LineItem[0..99999999]; // cardinality uses this max
5
6 }The maxRelationSize property doesn’t limit these values:
- The number of relationship declarations in a type
- The number of types in the constraint model
- The total component count across all relationships
Omit Unnecessary Relationships
When using the visual builder or the CML editor to create a CML code for a bundle, the system by default imports all the relationships for the selected bundle from the structure defined in Product Catalog Management (PCM). In large and complex CML code, some of these relationships may not be relevant to any constraint and can be potentially omitted.
To enable import of a subset of bundle components, add this property at the top of the constraint model CML file.
1property allowMissingRelations = "true";If your PCM bundle contains many relations but your CML code defines only one, the engine validates the model, but often returns a configuration failure. at run time. By setting allowMissingRelations = "true", you don’t have to define every relation found in the PCM (such as GeneralModels in the Relationship Ordering example) if they don’t require specific configuration logic in your CML file.
Here’s an example with the allowMissingRelations property.
1// 1. Enable skipping of unneeded relations from the Product Catalog (PCM)
2property allowMissingRelations = "true";
3
4type ConciseGeneratorBundle {
5 // Define only the specific accessory needed for this logic
6 relation enclosures : Enclosure;
7
8 // A simple variable to trigger the logic
9 int requiredKW = [100..5000];
10
11 // Logic: High power requirements force a specific enclosure type
12 // This omits other accessories like filters, batteries, and heaters [2, 3].
13 constraint(requiredKW > 2000 -> enclosures[ReinforcedEnclosure] == 1,
14 "Power levels above 2000kW require a Reinforced Enclosure.");
15}
16
17// 2. Define the accessory and its specific subtype
18type Enclosure ;
19type ReinforcedEnclosure : Enclosure;For more information, see Constraints.
To ensure stability at run time without the allowMissingRelations property, you must manually define every relation and type present in the PCM bundle, even if you don't intend to write logic for them. This creates large CML files with a high number of variables and components, which lead to performance degradation, and even timeout issues.
1// EXPENSIVE FIX: Mirroring everything
2type GeneratorSet {
3 relation engineModels : EngineModel; // Unused in CML logic
4 relation alternators : Alternator; // Unused in CML logic
5 relation fuelFilters : FuelFilter; // Unused in CML logic
6 relation starterMotors : StarterMotor; // Unused in CML logic
7 relation enclosures : Enclosure; // The only one we need
8 // ... potentially 15+ more relations ...
9
10 constraint(requiredKW > 2000 -> enclosures[ReinforcedEnclosure] == 1);
11}
12type Enclosure ;
13type ReinforcedEnclosure : Enclosure;Skip Type Generation for Types with Many Mapped Products
When you create a constraint model for a product whose type is mapped to a large number of products, either directly or through product classifications , the constraint engine loads all mapped product data into the model during model fetch, regardless of whether those products are used in your CML. In catalogs with hundreds or thousands of mapped products, the loading process can significantly increase model fetch and execution time, causing timeouts. To load only the types that you explicitly declare in your constraint model and skip generating types from unmapped product data, add the skipTypeGeneration property at the top of the constraint model CML file.
1property skipTypeGeneration = "true";When you set skipTypeGeneration = "true", the constraint engine skips type generation for all products not declared in the CML file, to optimize model storage. This property applies to types only and doesn't affect relationship loading or other model elements.
Use skipTypeGeneration = "true" when all of the following are true.
- A type in your constraint model is mapped to hundreds or thousands of products, either directly or through a product classification.
- Your CML defines constraints for only a subset of those mapped products.
- You experience slow load times or execution timeouts.
Example: skipTypeGeneration with a Large Classification Catalog
In this example, a GeneratorSet product is mapped to many products through a classification. The CML enforces duty-rating and engine constraints, but only needs two component types. Setting skipTypeGeneration = "true" at the top of the constraint model prevents the constraint engine from loading mapped products that the model doesn't use.
1// Skip loading all classification types from PCM.
2// Only the types explicitly declared in this file are loaded.
3property skipTypeGeneration = "true";
4type GeneratorSet : LineItem {
5 string DutyRating = ["Prime Power (PRP)", "Continuous Power (COP)", "Emergency Standby Power (ESP)"];
6 int requiredKW = [100..10000];
7 relation engine : Engine[1..1];
8 constraint(DutyRating == "Emergency Standby Power (ESP)" -> requiredKW >= 500,
9 "Emergency Standby Power requires at least 500 kW.");
10 constraint(DutyRating == "Prime Power (PRP)" -> engine[PrimePowerEngine] == 1,
11 "Prime Power duty rating requires a Prime Power Engine.");
12}
13// Declare only the types this constraint model requires.
14// Classification types not declared here are not loaded into the model.
15type Engine;
16type PrimePowerEngine : Engine;
17type ContinuousPowerEngine : Engine;Order Keyword
The order() keyword is used within a relation declaration to define the specific sequence in which the constraint engine evaluates and attempts to instantiate the child subtypes available in that relationship. This controls the prioritization of component selection.
Example: Relationship Ordering
1// --- Component Subtypes (Specific Generator Models) ---
2// Define a base type for generator models with a power attribute
3type GeneralModel {
4int powerKW = [0..3000]; // Explicit domain
5}
6// Specific subtypes that inherit from GeneralModel
7type GeneralModel2500 : GeneralModel {
8int powerKW = 2500;
9}
10type GeneralModel1750 : GeneralModel {
11int powerKW = 1750;
12}
13type GeneralModel900 : GeneralModel {
14int powerKW = 900;
15}
16// --- Parent Type (GeneratorSet) ---
17type GeneratorSet {
18// Required power defined by the parent (non-configurable)
19@(configurable = false)
20int requiredKW = [100..3000];
21// Relation Declaration using order()
22// Cardinality requires exactly one model to be selected.
23// order() sets the selection priority (2500 KW model is checked before 1750 KW model).
24relation GeneralModels : GeneralModel order(GeneralModel2500, GeneralModel1750, GeneralModel900);
25}