Skip to content
Carlo Barazzetta edited this page Dec 4, 2018 · 7 revisions

Contents - Index - Previous -Next **Adding Business Rules ** ----  Validation rules and other business related behavior is added to your business classes by adding the required code plus additional methods and properties to the class. Validation rules and side effects of changing the value of an attribute are often added to the setter method of the corresponding property. Complete validation of business objects before they are stored to the database can be added by overriding the BeforeStore method of the class. New objects can be initialized by overriding the Initialize method. For a complete list of the virtual methods of TInstantObject, please refer to the source code.

Note: BeforeStore is currently NOT called for embedded objects. Validation of embedded objects, however, can be done by using its owner's BeforeStore event.

Example 1 In InstantObjects you usually apply single-attribute business rules in the attribute's property setter method:

procedure TAddress.SetPostalCode(const Value: string);
begin
  // Validation: raise exceptions to prevent value assignment.
  if (Length(Value) <> 6) and (Value <> '') then
    raise Exception.Create('Postal Code must be filled with 6 chars');
  // Assignment: this code will usually be written by InstantObjects automatically.  
  _PostalCode.Value := Value;
  // Post-assignment: do things as a consequence of an attribute's value change
  // (see also the virtual method AttributeChanged).
  if (Value <> '') and (City = '') then
    GetDefaultCityByPostalCode(Value);
end;

If you need to apply business rules that involve more than one attribute, instead, you often use the BeforeStore virtual method (see Example 2).

When you code side effects, be aware that the property setters might be called more often than expected, for example when reading an object from an XML file or when you use the data-aware presentation layer. Here is an example:

procedure TShipment.SetMinShipDate(const Value: TDateTime);
begin
  // Assignment: this code will usually be written by InstantObjects automatically.  
  _MinShipDate.Value := Value;
  MaxShipDate := 0;    
end;

The intent of this code is to reset MaxShipDate whenever MinShipDate changes, so that a user, in a hypothetical data-entry scenario, will have to re-enter a value for MaxShipDate. But things might not work always as expected. For example, SetMinShipDate might be called after SetMaxShipDate when streaming in an object from a XML file. The lesson here is: use the property setters and the BeforeStore method only to apply real business rules (like "MaxShipDate must be equal to or greater than MinShipDate"), and code data-entry rules (like "whenever a value for MinShipDate is entered, MaxShipDate should be reset") at the data-entry level (that is, not in the model classes).

Example 2 Business rules that involve more than one attribute are usually applied in BeforeStore, which gets called whenever the Store method is called to write an object (back) to the storage. Example:

procedure TShipment.BeforeStore;
begin
  if MinShipDate > MaxShipDate then
    raise Exception.Create('Date range error');
  inherited;
end;

You initialize an object by overriding Initialize (if you need to apply initialization code both when a new object is created and when it is retrieved from the storage), or AfterCreate (if you need to apply initialization code for newly created objects only). There is also an AfterRetrieve method that you can override to apply initialization code only when an existing object is read from the storage and materialized in memory. Here is an example of AfterCreate:

procedure TContact.AfterCreate;
var
  vCategory: TCategory;
begin
  inherited;
  Id := InstantGenerateId;
  vCategory := TCategory.Retrieve('CAT000');
  try
    Category := vCategory;
  finally
    vCategory.Free;
  end;
end;
Clone this wiki locally