ActiveRecord represents a dynamic record in a particular database. Column meta data of the table are retrieved before the ActiveRecord instance is created. The following is an example for posts table.
public class Post extends ActiveRecord { }
If not specified, the table name an ActiveRecord class maps to is the plural form of the class name. And the database is the default database connection defined in the database.properties file.
Subclass should override the getTableName() method or the getConnectionName() method if non-default behavior is required. For example, the follow code defines a Post class that links with all_posts table in the blog_test database.
public class Post extends ActiveRecord { public String getTableName() { return "all_posts"; } public String getConnectionName() { return "blog_test"; } }
To establish relations with other models, all subclasses must implement the registerRelations() method by calling proper relationship setup methods: hasOne, belongsTo, hasMany, hasManyThrough, etc. For example:
public class Post extends ActiveRecord { public void registerRelations() { hasMany("comments"); } }
To modify an attribute of a record, you need to use one of the setData methods. Otherwise, the change may not be saved.
Conditions are often supplied in find, update and delete related methods. They help to construct WHERE clause of a SQL statement. Conditions can be provided in three ways:
conditionsSQL String specifies a SQL fragment which is used in where clause. For example:
conditionsSQL: "id in (1, 3, 5, 7) and content like '%Java%'"
conditionsSQL String and conditionsSQLData Array allows dynamic data in a SQL fragment. Each element in the array is corresponding to the value to be set to the conditionsSQL. Internally, the array is converted to a map with key starting from 1 for each element in the array. For example:
conditionsSQL: "first_name=? OR last_name=?" conditionsSQLData array: {"John", "Doe"}
conditionsSQL String and conditionsSQLData Map allows dynamic data in a SQL fragment. For example:
conditionsSQL: "first_name=?1 OR last_name=?2" conditionsSQLData map: 1=John, 2=Doe
The following chainable methods are introduced for retrieving data from the database.
Each method above allows us to retrieve data in a chainable way. For example, in a PetClinic application:
To retrieve a pet named Leo: ActiveRecord Leo = Pet.where("name='Leo'").getRecord(); The SQL equivalent of the above is: SELECT * FROM pets WHERE name = 'Leo' To retrieve all pets owned by owners with id 6 and 10, order by latest birth date: List pets = Pet.where("owner_id IN (6, 10)").orderBy("birth_date DESC").getRecords(); The SQL equivalent of the above is: SELECT * FROM pets WHERE owner_id IN (6, 10) ORDER BY birth_date DESC To retrieve a pet owner along with all the pets he/she has and each pet's type in one query (eager loading): ActiveRecord owner6 = Owner.where("owners.id=6").includes("pets=>visits, pets=>type").getRecord(); The SQL equivalent of the above is: SELECT OWNERS.ID AS OWNERS_ID, OWNERS.FIRST_NAME AS OWNERS_FIRST_NAME, OWNERS.LAST_NAME AS OWNERS_LAST_NAME, OWNERS.ADDRESS AS OWNERS_ADDRESS, OWNERS.CITY AS OWNERS_CITY, OWNERS.TELEPHONE AS OWNERS_TELEPHONE, PETS.ID AS PETS_ID, PETS.NAME AS PETS_NAME, PETS.BIRTH_DATE AS PETS_BIRTH_DATE, PETS.TYPE_ID AS PETS_TYPE_ID, PETS.OWNER_ID AS PETS_OWNER_ID, VISITS.ID AS VISITS_ID, VISITS.PET_ID AS VISITS_PET_ID, VISITS.VISIT_DATE AS VISITS_VISIT_DATE, VISITS.DESCRIPTION AS VISITS_DESCRIPTION, OWNERS_PETS.ID AS OWNERS_PETS_ID, OWNERS_PETS.NAME AS OWNERS_PETS_NAME, OWNERS_PETS.BIRTH_DATE AS OWNERS_PETS_BIRTH_DATE, OWNERS_PETS.TYPE_ID AS OWNERS_PETS_TYPE_ID, OWNERS_PETS.OWNER_ID AS OWNERS_PETS_OWNER_ID, TYPES.ID AS TYPES_ID, TYPES.NAME AS TYPES_NAME FROM OWNERS LEFT OUTER JOIN PETS ON OWNERS.ID=PETS.OWNER_ID LEFT OUTER JOIN VISITS ON PETS.ID=VISITS.PET_ID LEFT OUTER JOIN PETS OWNERS_PETS ON OWNERS.ID=OWNERS_PETS.OWNER_ID LEFT OUTER JOIN TYPES ON OWNERS_PETS.TYPE_ID=TYPES.ID WHERE OWNERS.ID = 6
Please notice that in all finder methods, options are replaced by chainable querying methods described above. options are used in specifying relations.
options can be either a string or a map.
In an option string, each name-value pair is separated by ';' character, while within each name-value pair, name and value strings are separated by ':' character. For example, an option string like the following:
is equivalent to a HashMap with the following entries:conditions_sql: id in (1, 2, 3); include: category, user; order_by: first_name, salary DESC; cascade: delete
key value -------------- ----- conditions_sql => id in (1, 2, 3) include => category, user order_by => first_name, salary desc cascade => delete
Options string or map are used in association methods such as hasMany and hasManyThrough. The following is a list of allowed properties: model, mapping, finder_sql, conditions_sql, include, join_type, order_by, unique, cascade. Please note that model property is only used in setting up relations.
Dynamic finders simulate Ruby-on-Rails's finder methods. These methods are findAllBy, findFirstBy, and findLastBy. The first input parameter of these methods is columns which is a string of column names linked by _and_, such as:
{columnName}_and_{columnName}_and_...
A client can call this method as follows:
Employee.findAllBy("firstName_and_lastName_and_age", {"John", "Doe", Integer.valueOf(29)}); Employee.findAllBy("city", {"LA"});
See java doc of {@link com.scooterframework.common.validation.Validators Validators} class.
@author (Fei) John Chen
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|