-
Notifications
You must be signed in to change notification settings - Fork 6
Second Tutorial Part 10: Behavior Customization
Previous | Main | Next |
---|---|---|
<-- Part 9 | Main | Part 11 --> |
An important part of the Tilda architecture is that it separates the generated classes from the application-level classes that you can customize. Not only can you add new methods in either the Factory or Data classes as we have highlighted in this tutorial, but there are also methods you can override. Based on the object's definition, a variety of methods with empty bodies will be defined in the generated application classes.
🎈 NOTE: Default implementations of required overridable methods will be generated the first time a class is introduced in the system. If an object's definition is changed during the course of development, then the application-class won't be re-generated and a compiler error might occur as a result. For example, you might change the OCC
status of a class and suddenly your App class should define its own touch
method. Most modern IDEs will flag this and even offer a quick way to add the method to our class which you can then complete with an implementation.
For the purpose of this tutorial, we'll look at a Dummy
table in our tutorial defined as such:
- We'll turn off OCC
-
nameNorm
is an AUTO column -
charCount
is a CALCULATED column -
updated
is a DATETIME column to keep track of our own life cycle timestamp
,{ "name":"Dummy"
,"description":"Dummy class for testing purpose"
,"occ":false
,"columns":[
{ "name":"nameFirst", "type":"STRING" , "size":255, "nullable":false
,"description":"A first name"
}
,{ "name":"nameLast" , "type":"STRING" , "size":255, "nullable":false
,"description":"A last name"
}
,{ "name":"nameNorm" , "type":"STRING" , "size":255, "nullable":false
,"mode":"AUTO"
,"description":"A normalized name as upper(nameLast+','+nameFirst)."
}
,{ "name":"charCount", "type":"INTEGER" , "nullable":true
,"mode":"CALCULATED"
,"description":"An app-only count of the character length of nameNorm."
}
,{ "name":"updated" , "type":"DATETIME" , "nullable":true
,"description":"A timestamp to track this row's life cycle"
}
]
,"primary": { "autogen": true, "keyBatch": 500 }
,"indices": [
{ "name":"nameNorm", "columns": ["nameNorm"] }
]
}
The generated Java application class will look like:
public class Dummy_Data extends tilda_tutorial.data._Tilda.TILDA__DUMMY
{
protected static final Logger LOG = LogManager.getLogger(Dummy_Data.class.getName());
public Dummy_Data() { }
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// Implement your customizations, if any, below.
/////////////////////////////////////////////////////////////////////
@Override
protected void setNameNorm()
throws Exception
{
// Do something to set the value of the auto field.
...
}
@Override
public int getCharCount()
{
// return some value
...
}
@Override
protected boolean beforeWrite(Connection C) throws Exception
{
// Do things before writing the object to disk, for example, take care of AUTO fields.
return true;
}
@Override
protected boolean afterRead(Connection C) throws Exception
{
// Do things after an object has just been read form the data store, for example, take care of AUTO fields.
return true;
}
@Override
public boolean touch(Connection C) throws Exception
{
// Do things here to update your custom life-cycle tracker fields, like timestamp, if any.
... something like setLastUpdatedNow();
// the write the object to complete the touch operation.
return write(C);
}
}
🎈 NOTE: The methods that require an implementation are generated with code that explicitly induces compile errors so it's clear that immediate attention is needed. A body needs to be provided for an implementation that only you can write.
Getters and setters are declared as final in the generated Data base class. They are not overridable and this decision was not taken lightly: because the behavior of a setter or getter is complex, that introduced too many issues in earlier versions of the framework.
However, if a column is defined as "mode":"CALCULATED"
, the getter will be declared as abstract in the base class and therefore will need to be concretized in the application-level Data class. defining a column as CALCULATED delegates the column to only exist in the application-space: no column will actually be declared in the database. It is then your responsibility to provide a getter implementation. Of course, no setter will be generated.
Additionally, if a column is defined as "mode":"AUTO"
, the regular setter will be protected and a protected "auto" setter method without any parameter will be generated. That method will be called by the framework right before a database write (insert of update) and the beforeWrite()
method is called.
By default, all objects are OCC-enabled and key life-cycle management columns such as created
, lastpdated
and deleted
are automatically generated. However, if the object is declared with "occ":false
, those fields won't be defined and an abstract touch()
method will defined.
🎈 NOTE: The default generated method will cause a compile error and will require immediate attention. A body needs to be provided for an implementation that only you can write.
Before an object is written to the database, the beforeWrite()
method is called. After an object has been read from the database, the afterRead()
method is called.
Typically, logic in there can perform additional validation, logging, keep track of cached values which may be used by AUTO or CALCULATED fields etc...
Previous | Main | Next |
---|---|---|
<-- Part 9 | Main | Part 11 --> |