Version 26 (modified by 11 years ago) ( diff ) | ,
---|
Super-Entities
Table of Contents
Introduction
Sometimes it is useful to link the same component to multiple master entities without introducing a separate foreign key constraint for each master.
Example: both warehouses and offices have contact persons. Instead of creating separate warehouse_contact and office_contact components, you can make use of the super-entity concept to link a single site_contact component to both entities.
To achieve this, S3 supports a special type of key tables called Super-Entities (referring to the fact that they constitue a generalization concept):
A super-entity stores (tablename, uuid) pairs which identify records across multiple tables, and the primary key of the super-entity (super-key) can then be used for foreign key constraints to link components. The primary key of the super-entity is usually referred to as super-key, and the respective foreign key constraints are called super-link.
The super-entity concept is implemented in S3Model, and supported by both S3CRUD and S3Import. Custom methods can make use of the current.s3db API to handle super-entities as described below.
API
To simplify the handling of super-entities in the model, S3Model provides a unified API for super-entities:
Defining a Super-Entity
A super-entity can be defined using the super_entity()
method of S3Model:
class MyModel(S3Model): def model(self): # Define a dict with nice names for the instance types: my_instance_types = { "my_instance_tablename": T("Nice name for the instance type"), } # Define the super-entity tablename = "my_super_entity" table = self.super_entity(tablename, "my_super_id", # specify the super ID my_instance_types, # specify the instance types Field("start_date", "datetime"), # shared field location_id()) # shared field
Shared fields will mirror the values from the respective instance record, which allows easy access without need to join multiple tables.
If the names of shared fields are different in certain instance tables, you can define a field mapping when you configure the instance table:
# Define the instance table tablename = "my_instance_table" table = self.define_table(tablename, Field("first_date", "datetime"), Field("last_date", "datetime"), *s3_meta_fields()) # Configure the instance table self.configure("my_instance_table", # Configure the super entity super_entity = "my_super_entity", # Map the "first_date" field in my_instance_table to "start_date" in my_super_entity my_super_entity_fields = {"start_date": "first_date"}, )
Defining an Instance of a Super-Entity
To make a table an instance of a super-entity, you can use s3db.configure()
:
s3db.configure(table, super_entity = db.sit_situation)
By default, all fields that the table and the super-entity have in common will be mirrored in the super-entity ("shared fields"). You can override this by specifying a list of fields to be mirrored by the super-entity.
s3db.configure(table, super_entity = db.sit_situation, sit_situation_fields = ["datetime"])
In case your table uses different names for the shared fields, you can use a dict instead to specify a mapping:
s3db.configure(table, super_entity = db.sit_situation, sit_situation_fields = dict(datetime="timestmp", location_id="location_id"))
Linking to a Super-Entity
Both, instance tables as well as shared components need to be linked to the super-entity. This can be done by inserting a super-key field into the instance/component table which must have the same name as the primary key of the super-entity. You can use the super_link()
function as a DRY method for this:
tablename = "pr_presence" table = db.define_table(tablename, super_link("pe_id", "pr_pentity"), super_link("sit_id", "sit_situation"), # sit_id ...)
Note: super_link
generates a Field
instance - if you just need the name of the super-key field, you can use:
sk = s3db.super_key(db.pr_pentity) # returns the string "pe_id"
Updating a Super-Entity
If you use s3_rest_controller() for CRUD, it will automatically create, update and delete super-entities as necessary.
Otherwise, or if you manipulate records outside s3_rest_controller, you have to update all super-entities which an instance table implements whenever you create, update or delete a record in that table.
To do this, you can use:
s3db.update_super(table, record)
where table
is the instance table and record
the newly created/updated record.
In case you're going to delete a record from an instance table, you may use:
s3db.delete_super(table, record)
before you delete the record, where table
is the instance table and record
the record to be deleted.
Attachments (1)
-
super_entity.png
(38.8 KB
) - added by 11 years ago.
Super-Entity Relationships
Download all attachments as: .zip