Skip to content

Relationship#

Bases: SsasRenameRecord

TBD.

SSAS spec: Microsoft This class represents a relationship between two tables in a Tabular model.

Source code in pbi_core/ssas/model_tables/relationship/relationship.py
@define()
class Relationship(SsasRenameRecord):
    """TBD.

    SSAS spec: [Microsoft](https://learn.microsoft.com/en-us/openspecs/sql_server_protocols/ms-ssas-t/35bb4a68-b97e-409b-a5dd-14695fd99139)
    This class represents a relationship between two tables in a Tabular model.
    """

    cross_filtering_behavior: CrossFilteringBehavior = field(eq=True)
    from_column_id: int = field(eq=True)
    from_cardinality: int = field(eq=True)
    from_table_id: int = field(eq=True)
    is_active: bool = field(eq=True)
    join_on_date_behavior: JoinOnDateBehavior = field(eq=True)
    model_id: int = field(eq=True)
    name: str = field(eq=True)
    relationship_storage_id: int | None = field(eq=True, default=None)
    relationship_storage2_id: int | None = field(eq=True, default=None)
    """wtf these are two different fields in the json??!!??"""
    relationship_storage2id: int | None = field(eq=True, default=None)
    """wtf these are two different fields in the json??!!??"""
    rely_on_referential_integrity: bool = field(eq=True)
    security_filtering_behavior: SecurityFilteringBehavior = field(eq=True)
    state: Final[DataState] = field(eq=False, on_setattr=setters.frozen, default=DataState.READY)
    to_cardinality: int = field(eq=True)
    to_column_id: int = field(eq=True)
    to_table_id: int = field(eq=True)
    type: RelationshipType = field(eq=True)

    modified_time: Final[datetime.datetime] = field(eq=False, on_setattr=setters.frozen, repr=False)
    refreshed_time: Final[datetime.datetime] = field(eq=False, on_setattr=setters.frozen, repr=False)

    _commands: RenameCommands = field(default=SsasCommands.relationship, init=False, repr=False, eq=False)

    def from_table(self) -> "Table":
        """Returns the table the relationship is using as a filter.

        Note:
            In the bi-directional case, this table is also filtered

        """
        return self._tabular_model.tables.find({"id": self.from_table_id})

    def to_table(self) -> "Table":
        """Returns the table the relationship is being filtered.

        Note:
            In the bi-directional case, this table is also used as a filter

        """
        return self._tabular_model.tables.find({"id": self.to_table_id})

    def from_column(self) -> "Column":
        """The column in the from_table used to join with the to_table."""
        return self._tabular_model.columns.find({"id": self.from_column_id})

    def to_column(self) -> "Column":
        """The column in the to_table used to join with the from_table."""
        return self._tabular_model.columns.find({"id": self.to_column_id})

    def model(self) -> "Model":
        """The DB model this entity exists in."""
        return self._tabular_model.model

    def variations(self) -> set["Variation"]:
        return self._tabular_model.variations.find_all({"relationship_id": self.id})

    def children_base(self) -> frozenset["LinkedEntity"]:
        return LinkedEntity.from_iter(self.variations(), by="variation") | LinkedEntity.from_iter(
            self.annotations(),
            by="annotation",
        )

    def parents_base(self) -> frozenset["LinkedEntity"]:
        """Returns all tables and columns this Relationship is dependent on.

        Note:
            Although relationships have direct links to tables via the from_table_id and to_table_id,
            they are actually dependent on the columns that make up those tables. Therefore, `recursive=False`
            returns only the from_column and to_column as dependencies.

        """
        return LinkedEntity.from_iter({self.from_column()}, by="from_column") | LinkedEntity.from_iter(
            {self.to_column()},
            by="to_column",
        )

    def __repr__(self) -> str:
        return f"{self.__class__.__name__}({self.id}, from: {self.pbi_core_name()}, to: {self.pbi_core_name()})"

relationship_storage2_id class-attribute instance-attribute #

relationship_storage2_id: int | None = field(eq=True, default=None)

wtf these are two different fields in the json??!!??

relationship_storage2id class-attribute instance-attribute #

relationship_storage2id: int | None = field(eq=True, default=None)

wtf these are two different fields in the json??!!??

from_column #

from_column() -> Column

The column in the from_table used to join with the to_table.

Source code in pbi_core/ssas/model_tables/relationship/relationship.py
def from_column(self) -> "Column":
    """The column in the from_table used to join with the to_table."""
    return self._tabular_model.columns.find({"id": self.from_column_id})

from_table #

from_table() -> Table

Returns the table the relationship is using as a filter.

Note

In the bi-directional case, this table is also filtered

Source code in pbi_core/ssas/model_tables/relationship/relationship.py
def from_table(self) -> "Table":
    """Returns the table the relationship is using as a filter.

    Note:
        In the bi-directional case, this table is also filtered

    """
    return self._tabular_model.tables.find({"id": self.from_table_id})

model #

model() -> Model

The DB model this entity exists in.

Source code in pbi_core/ssas/model_tables/relationship/relationship.py
def model(self) -> "Model":
    """The DB model this entity exists in."""
    return self._tabular_model.model

parents_base #

parents_base() -> frozenset[LinkedEntity]

Returns all tables and columns this Relationship is dependent on.

Note

Although relationships have direct links to tables via the from_table_id and to_table_id, they are actually dependent on the columns that make up those tables. Therefore, recursive=False returns only the from_column and to_column as dependencies.

Source code in pbi_core/ssas/model_tables/relationship/relationship.py
def parents_base(self) -> frozenset["LinkedEntity"]:
    """Returns all tables and columns this Relationship is dependent on.

    Note:
        Although relationships have direct links to tables via the from_table_id and to_table_id,
        they are actually dependent on the columns that make up those tables. Therefore, `recursive=False`
        returns only the from_column and to_column as dependencies.

    """
    return LinkedEntity.from_iter({self.from_column()}, by="from_column") | LinkedEntity.from_iter(
        {self.to_column()},
        by="to_column",
    )

to_column #

to_column() -> Column

The column in the to_table used to join with the from_table.

Source code in pbi_core/ssas/model_tables/relationship/relationship.py
def to_column(self) -> "Column":
    """The column in the to_table used to join with the from_table."""
    return self._tabular_model.columns.find({"id": self.to_column_id})

to_table #

to_table() -> Table

Returns the table the relationship is being filtered.

Note

In the bi-directional case, this table is also used as a filter

Source code in pbi_core/ssas/model_tables/relationship/relationship.py
def to_table(self) -> "Table":
    """Returns the table the relationship is being filtered.

    Note:
        In the bi-directional case, this table is also used as a filter

    """
    return self._tabular_model.tables.find({"id": self.to_table_id})