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.