Docs‎ > ‎API Creator‎ > ‎Specify your Business Rules‎ > ‎

Insert Into From

It is a very common requirement to copy one or more source rows to target rows. A corollary requirement is that the created target rows are usually children of the source rows, and require proper initialization of their attributes. The general concept is loosely analogous to the Insert Into Select From SQL command.

You can use the following services:
  • Auditing. This is a copy of the current row, with provisions for audit conditions and target attribute initialization.
    Service: InsertChildFrom
  • Deep Copy. It is a common requirement to "clone" a Business Object, meaning a "master" and its related objects. For example, a customer might like to create a new order by copying an old one.
    Service: copyMyAttributesFrom
  • Bill of Materials Explosion. This pattern is a variant of a deep copy and can be solved with just a few rules.
    Service: insertChildrenFrom

Solution: Insert Into From

We can provide such services with ad hoc Java code, either in our application or (better, for re-use!) in our Business Logic Components. But this pattern is so prevalent that this is simply reinventing the wheel.  

We can save cost and increase agility with re-usable InsertIntoFrom service for copying. We can then invoke these from our Action rules under the appropriate conditions. This class provides the set of similar services.

Examples

Auditing

The most common case of auditing follows this pattern:

When you alter a source object meeting an audit conditioncopy the source object to a child target objectinitializing appropriate target attributes.

The Audit Salary Changes example follows this pattern:

When you alter a source object Employee meeting an audit condition of salary changes, copy the source object to a child target object EmployeeAudit, initializing appropriate target attributes to record the old salary. Live API Creator supplies the following event rule in the source object employees:

if (row.baseSalary != oldRow.baseSalary)
SysLogic.insertChildFrom("employee_audits", logicContext);

From our pattern:
  • The source object employees is the origin of the rule.
  • The audit condition is the salary change.
  • The child target object employee_audits is the first parameter.
Common to all variations of this pattern is the initialization of created objects.

Target Object Attribute Initialization

All variations of the auditing pattern create one or more target objects. A mechanism is required to initialize the attributes of such created objects:
  • copy like-named attributes from parent

  • The system next copies like named attributes from the source to the target.  In the example above, this will set the Salary attribute.

    • set foreign key
    Insert Into creates one or more children of the source object. Set the foreign key of the created child. In this example, the target child EmployeeAudit is linked to the source parent EmployeeWithin a relationship, a child is the table containing the foreign key on the "many" side. For example, Purchaseorder is a child to Customer. PUT/POST JSON provides mechanisms to associate a child with its parents.

    Live API Creator uses the heuristic to introspect the target (child) for an entity-type method that returns the type of the source (parent).

    Note: An exception is raised in the rare case where more than one such method is found.
    • copy like-named attributes from source
    This applies only to insertChildrenFrom.  The system next copies like named attributes from the children rows being copied. In this example, the Salary attribute is set.
    • target object derivation rules
    Target objects are saved after they are created, which invokes their business logic. You can define formulas on these objects.

    Deep Copy

    The copy operation often includes not just (scalar) attributes, but also related data. For example, if we want to create a new Purchaseorder from an existing one, we need to clone both the Purchaseorder and the Lineitems.

    Business logic is initiated only when performing transactions (inserts, updates and deletes) to the database. You can trigger this logic from either the source (copied) object, or from the target (inserted) object. You can also build services which expose the functionality more explicitly. Unlike manually coded services, such services can be thin, since they can invoke the domain-encapsulated business logic.

    Copy from Target

    The clonePurchaseorder example uses the InsertIntoFrom#copyMyAttributesFrom service. This example provides an interface where the client inserts a Purchaseorder, setting an Entity attribute (clonedFrom) as the source of the deep copy. The functionality is invoked by way of an action rule:

    /**
    * Deep copy of clonedFrom PO (if non-null) to this new PO.
    */
    @Action
    public void actionClonedFromPurchaseorder() {
    if (logicContext.verb == Verb.INSERT && logicContext.logicNestLevel == 0 &&
    purchaseorder.clonedFrom != null) {
    String[] deepCopy = ["lineitems", "lineitemUsages"]
    InsertIntoFrom.copyMyAttributesFrom (
    logicContext, // indicates current object (copy target)
    purchaseorder.clonedFrom, // copy source
    deepCopy) // collections to copy
    }
    }

    Copy from Source

    Another design approach is to update an existing order, whose logic create a copy of itself. That example is described here.

    Alert: using transient attributes

    You may be tempted to set an transient attribute to trigger the copy operations.  This is actually an excellent idea, but will fail since Hibernate detects updates which involve only transient attributes, and prunes the update.  This of course prevents logic execution.

    Bill of Materials Explosion

    When ordering a Product that is a kit, we want to reduce inventory for each of the components of the kit. The key requirement is to populate the SubItems for a kit-based Lineitem (see the database structure), by copying the ProductBillofMaterials to the subItems.  You can do this with the following explodeBillofMaterials Event rule on Lineitem:

    if (logicContext.verb == "INSERT" && row.product.count_components > 0) {
    SysLogic.insertChildrenFrom("lineitems", row.product.components, logicContext);
    }
    The remaining logic (four rules) is simply to properly arrange for quantities (i.e., if you buy two planes, you need eight engines). The Bill Of Materials Explosion example is an advanced example used in the Training.

    Insert Into Operation

    While there are varying formulations of InsertIntoFrom, we can illustrate their operation by describing the example. The basic idea is to create a series of (target) Lineitem objects, one for each (source) component object.

    The following lists the key players:
    • Parent - the object that issues the InsertIntoFrom, here a Lineitem
    • Source - the objects being copies, here a list: lineitem.product.components
    • Target - the class in which rows are inserted - here, also Lineitem (the created sub items)
    The system iterates over the Source list, creating a target instance that is initialized as follows:
    • copyAttributesFromTo copies like named attributes from the Parent to the Target
    In our example, the Target SubItem is linked to the Order
    • link the Target to the Parent (there is a presumed one-to-many relationship from the Parent to the Target)
    This links the Target SubItem to the Parent Lineitem (role name: kitItem)
    • link the Target to the Source (there is an optional one-to-many relationship from the Parent to the Target, the caller specifies whether this linkage exists with the aLinkToSource parameter
    In our example, this linkage does not occur - the helper used sets the aLinkToSource = false
    • copyAttributesFromTo copies like named attributes from the Source to the Target
    In our example, this copies ProductBillofMaterials.kitNumberRequired to the Target (SubItem) kitNumberRequired
    • after the copy operations, Target logic is invoked
    In our example, lineitems rules compute qtyOrdered as

    row.kitNumberRequired * row.kitItem.qtyOrdered

    The copyAttributesFromTo copies like-named attributes, as noted above; note that:
    • Primary key attributes are not copied
    • Non-null values are over-written, so, for example, copied Source values override copied Parent values