Modeling
All data model classes extend from the class in the Dari framework. All fields in a subclass of Record
are persisted as a database record when the object is saved. In addition, Dari creates and saves an object type definition that contains the metadata of the model.
See also:
The following is a simple model of an article. It extends the Dari Record
class and includes getter and setter methods for the headline
, body
, and leadImage
fields. All fields in a Record
object are persisted to the underlying database, with the exception of fields marked with the Java transient
keyword.
import com.psddev.dari.db.*;
public class Article extends Record {
@Required /* Annotation specifies that value is required for headline field */
@Indexed /* Annotation specifies that field is to be indexed */
private String headline;
@Indexed
private String body;
private Image leadImage;
public String getHeadline() {
return headline;
}
public void setHeadline(String headline) {
this.headline = headline;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public Image getLeadImage() {
return leadImage;
}
public void setLeadImage(Image leadImage) {
this.leadImage = leadImage;
}
}
For each model created, Dari persists an object type definition, represented by an class. An ObjectType
defines the structure and the metadata of the model. This includes the core model class, such as Article
in the above example, and any modifications, augmentations, or substitutions to the core model class. When a model is updated, the object type definition is updated.
The ObjectType#getInstance
method returns an object type definition as a JSON object. For example, using the Code Editor, you can return the object type definition for the Article
model class.
return ObjectType.getInstance(psddev.dari.test.Article.class);
The returned object is a comprehensive metadata listing that includes attributes about the model class, its fields, and its relationships to other classes. For example, the following JSON fragment for the Article
model shows information about two of the model fields, headline
and author
. The headline
field is declared in the core Article
class. However, the author
field is declared in ArticleModification
(not shown), a modification that extends the Article
class with a new field.
{
"fields": [{
"isRequired": true,
"java.field": "headline",
"java.declaringClass": "com.psddev.dari.test.Article"
},
{
"isRequired": false,
"java.field": "author",
"java.declaringClass": "com.psddev.dari.test.ArticleModification"
} ]
}
The next JSON fragment shows that there are indexes for two fields in the Article
model: headline
and body
. The indexes are a result of the @Indexed
annotations applied to these fields in the Article
class.
{
"indexes": [{
"field": "headline",
"fields": ["headline"],
"type": "text",
"isUnique": false,
"caseSensitive": false,
"visibility": false,
"java.declaringClass": "com.psddev.dari.test.Article"
},
{
"field": "body",
"fields": ["body"],
"type": "text",
"isUnique": false,
"caseSensitive": false,
"visibility": false,
"java.declaringClass": "com.psddev.dari.test.Article"
}
]
}
The object type definition also specifies other classes that contribute to the Article
model. In addition to the modification class, an augmentation, ArticleAugmentation
, is applied to the Article
core class.
{
"java.objectClass": "com.psddev.dari.test.Article",
"java.modificationClasses": [
"com.psddev.dari.test.Article", "com.psddev.dari.test.ArticleModification"
],
"java.superClasses": [
"com.psddev.dari.test.Article", "com.psddev.dari.db.Record", "java.lang.Object"
],
"java.assignableClasses": [
"com.psddev.dari.test.Article", "com.psddev.dari.db.Record", "java.beans.BeanInfo", "java.lang.Cloneable", "java.lang.Comparable", "com.psddev.dari.util.HtmlObject", "com.psddev.dari.db.Recordable", "java.lang.Object"
],
"augmentationClassNamesByTargetClassName": {
"com.psddev.dari.test.Downloadable": ["com.psddev.dari.test.ArticleAugmentation"]
}
}
ObjectType
also contains methods for getting specific metadata items, such as fields, methods, and indexes.
A object is linked to state information that is also persisted to the database. A Record
object’s state is represented by a object that is retrievable from Record
. Changes to either the Record
or to the State
object are copied to its associated object. Record
and State
include the same save methods, as Record
delegates to State
to execute those methods.
You can get a Record
object’s state in one of the following ways:
State state = object.getState();
/* OR */
State.getInstance(object);
State
provides numerous methods that return comprehensive information about a Record
object. For example, there are methods to return an object’s metadata and instance data. The getStatus
method returns , indicating if the object is deleted, reference-only, or saved. For Image
or Video
objects to which the @Recordable.PreviewField annotation is applied, the getPreview
method returns the storage item that Brightspot uses to preview the object.
State
includes methods to describe an object’s visibility. isVisible
indicates if an object is hidden from queries for published objects. For hidden objects that implement Visibility labels, getVisibilityLabel
returns the object’s current non-published state. (For additional information about how to exclude objects in queries, see Excluding records from queries with visibility labels.)
A State
object reflects the state of the original Record
object and any other objects that might subsequently be linked to the original object. Linked objects are modifications and augmentations. State
provides methods to work with linked objects. The isInstantiableTo
method indicates if an original object is linked to modifications or augmentations. If it is, the as
method converts the state of an original object to an instance of a modification or augmentation. The linkObject
and unLinkObject
methods link and unlink related objects to the state of the Record
object.
All subclasses of Record
must have a nullary constructor. If you wish to have a constructor with arguments, you must also provide a nullary constructor.
Additionally, Record
provides an afterCreate
API which is called by the nullary constructor of the Record
class. It does nothing by default, but you can override the method to perform operations which need to occur when objects are created.
Be advised that the nullary constructor (and therefore afterCreate
) will be called every time the object is instantiated out of the database. If you want code to run only once, when an object is created for the first time, use the following pattern in a nullary constructor or the afterCreate
method:
if (getState().isNew()) {
/* One-time operations here */
}