109 Entity Creation and Base Updates
Constructing an entity value is not the same thing as making that entity part of persistent database state. The constructor expression produces an entity value with the supplied attributes. A database-state update makes that value observable from a persistent root or base collection.
proc recordShipment(ShipmentsSystem system, Supplier supplier, Part part, Integer qty)
{
var Shipment shipment = Shipment {
supplier = supplier,
part = part,
qty = qty
};
system.shipment ∪= shipment;
}
The declaration var Shipment shipment = ...; creates a local program variable
holding an entity value. It does not insert a row, allocate persistent storage,
or update a database partition. The statement system.shipment ∪= shipment;
is the database-state update: it adds the shipment to the base shipment
extension of the persistent ShipmentsSystem.
Base Attributes
A base attribute is an attribute stored directly on the receiver's state. Base attributes have location denotations and may be update targets when the receiver is mutable program state or persistent database state.
entity ShipmentsSystem
{
Supplier supplier*;
Part part*;
Shipment shipment*;
}
In this shape, supplier, part, and shipment are base attributes of
ShipmentsSystem. Updating system.shipment changes the stored shipment
extension.
Derived and Inverse Attributes
A derived attribute is defined by an expression. It is read-only unless the specification gives it an explicit update rule. An inverse attribute is a derived attribute: it is calculated by inverting a base path.
entity Supplier
{
Integer id;
String name;
→ Shipment shipment* = inverse shipment.supplier;
}
The path supplier.shipment is useful for queries, but it is not an ordinary
update target. The update that records a shipment writes the base collection
from which the inverse is derived:
system.shipment ∪= shipment; // base update
supplier.shipment ∪= shipment; // invalid without an explicit view-update rule
This keeps the write path explicit. A view-update rule may later define how a particular derived attribute can be updated, but no such rule is inferred merely because a derived attribute is navigable.
Keyed Extension Updates
For any entity type E, every key of E must be unique within the extension of
any attribute of type E. This affects updates to locations holding such
extensions; it does not affect construction of entity values. Constructing an
entity value is an ordinary expression and neither reads nor updates an
extension.
entity Shipment
{
Supplier supplier;
Part part;
Integer qty;
key {supplier, part};
}
Suppose a location holding an extension of Shipment already contains a
shipment with a particular supplier and part. Applying ∪= to that
location with a new Shipment having the same supplier and part replaces
the existing member with the new value. This is a keyed extension update, not
an effect of the entity constructor. If no member has the same key, the new
value is inserted.
The design is less obvious when an entity type declares multiple candidate keys and the supplied value matches different existing members by different keys. Predica could define any of the following behaviours:
- reject the update because the candidate keys select conflicting existing members;
- replace every matching member with the supplied value, thereby merging those members;
- give one candidate key precedence for replacement, while continuing to require every candidate key to be unique in the resulting extension.
This remains a language-design choice. The provisional recommendation is to reject an update that matches more than one existing member. That rule avoids an implicit merge and treats all candidate keys symmetrically. An explicit merge operation could be provided separately if merging is required.