-
Notifications
You must be signed in to change notification settings - Fork 27
Using Models
A pair of a case class and its companion object is mapped to a database table.
The case class, extends com.github.aselab.activerecord.ActiveRecord, corresponds to records in the table and provides CRUD logic, etc.
The companion object, extends com.github.aselab.activerecord.ActiveRecordCompanion[T], corresponds to the table and provides query logic, etc.
Note :
Tis a type of corresponding ActiveRecord class
package models
import com.github.aselab.activerecord._
case class Person(var name: String, var age: Int) extends ActiveRecord
object Person extends ActiveRecordCompanion[Person]By default, each field is mapped to a column in the database, where the convention for column names is all lower case separated by underscores. (e.g.createdDate maps onto a column created_date.)
It is possible to override a field’s column name with the com.github.aselab.activerecord.dsl.Column annotation. For example to change the name you can do:
package models
import com.github.aselab.activerecord._
import dsl._
import java.util.Date
case class Group(
var name: String,
@Column("CreatedDate") createdDate: Date
) extends ActiveRecord
object Group extends ActiveRecordCompanion[Group]if set attribute value for transient field, you can use the com.github.aselab.activerecord.dsl.Transient annotation.
package models
import com.github.aselab.activerecord._
import dsl._
case class User(
var name: String,
) extends ActiveRecord {
@Transient var fieldName = "Not saving the field"
}
object User extends ActiveRecordCompanion[User]Note : More information is available in the Squeryl manual.
The default (and strongly recommended) way of mapping nullable columns to fields is with the Option[] type.
If you use Scala ActiveRecord to create (or generate) your table schema, all fields have a not null constraint, and Option[] fields are nullable.
package models
import com.github.aselab.activerecord._
import dsl._
case class Foo(var foo: String) extends ActiveRecord
object Foo extends ActiveRecordCompanion[Foo]
case class Bar(var bar: Option[String]) extends ActiveRecord
object Bar extends ActiveRecordCompanion[Bar]
...
Foo(null).save() // => throws Exception 'NULL not allowed for column "FOO";'
Bar(None).save() // => OKStringBooleanIntLongFloatDoubleBigDecimaljava.sql.Timestampjava.util.Datejava.util.UUID
With mixin Timestamps trait, automatically timestamps create and update operations.
(The timestamp table columns are created_at and updated_at. In model, createdAt, updatedAt)
case class Foo(var foo: String) extends ActiveRecord with Timestamps
object Foo extends ActiveRecordCompanion[Foo]
// val foo = Foo("foo").create()
// foo.createdAt // => created Timestamp
// foo.updatedAt // => updated TimestampWith mixin Datestamps trait, automatically timestamps create and update operations.
(The datestamp table columns are created_on and updated_on. In model, createdOn, updatedOn)
case class Foo(var foo: String) extends ActiveRecord with Datestamps
object Foo extends ActiveRecordCompanion[Foo]
// val foo = Foo("foo").create()
// foo.createdOn // => created Date
// foo.updatedOn // => updated DateThe Optimistic trait support optimistic locking. Each update to the record increments the occVersionNumber column and the locking facilities ensure that records instantiated twice will let the last one saved raise a StaleObjectException if the first was also updated. Example:
case class Book(var name: String, var price: Int) extends ActiveRecord with Optimistic
object Book extends ActiveRecordCompanion[Book]
val b1 = Book.head
val b2 = Book.head
b1.name = "update"
b1.save
b2.name = "other update"
b2.save // throws com.github.aselab.activerecord.StaleObjectExceptionOptimistic locking will also check for stale data when objects are destroyed. Example:
val b1 = Book.head
val b2 = Book.head
b1.name = "update"
b1.save
b2.delete // throws com.github.aselab.activerecord.StaleObjectExceptionA database schema is defined in the schema object that extends com.github.aselab.aselab.ActiveRecordTables.
Note : Its fully qualified class name must be written in
application.conf. (Database Settings)
Declare a val field with table[T] in the schema object.
Note :
Tis a type of ActiveRecord classes
package models
import com.github.aselab.activerecord._
import com.github.aselab.activerecord.dsl._
object Tables extends ActiveRecordTables {
val people = table[Person]
// You can also specify its table name. Default is the same name as its class.
// val people = table[Person]("other_table_name")
}Note : More information is available in the Squeryl manual.
Table column properties (unique, index, auto_increment etc.) are also defined table[T].
For example to change the column attributes you can do:
package models
import com.github.aselab.activerecord._
import com.github.aselab.activerecord.dsl._
object Tables extends ActiveRecordTables {
val people = table[Person]
on(people)(t => declare(
t.name is(unique, indexed("idxPeopleName"), dbType("varchar(255)")),
t.name defaultsTo("defaultName"),
t.age is(indexed)
))
}You must call initialize method of the schema object before using model classes.
And then you should call cleanup method to release all resources.
If you are using Play with Guice to DI initialization logic with an AbstractModule, it is possible that the default scala-activerecord play plugin may have not fired yet and you will get a com.github.aselab.activerecord.SchemaSettingException. To fix this, you should ensure that your module encapsulates calls to initialize and cleanup against your schema tables definition.
Tables.initialize
...
Tables.cleanupPerson("person1", 15).save()Person.findBy("name", "person1") // => Some(Person("person1", 15))
Person.findBy("name", "not exists"). // => None
Person.findBy("name" -> "person1", "age" -> 15) // => Some(Person("person1", 15))
Person.where(_.age gte 10).toList // => List(Person("person1", 15))
Person.all.toList // => List(Person("person1", 15))The fields should be declared as var.
val person = Person.findBy("name", "person1").get
person.name = "new name"
person.age = 21
person.saveIf you want to make it immutable, you should declare all fields as constructor arguments and use auto generated copy method of the case class.
Note : You must also declare
override val idbecauseidfield is declared in base class.
case class Person(name: String, age: Int, override val id: Long = 0) extends ActiveRecord
val person = Person.findBy("name", "person1").get
person.copy(name = "new name", age = 21).save// Delete single record
val person = Person.findBy("name", "person1").get
person.delete
// Delete all records
Person.deleteAllThe transaction and inTransaction functions are available.
import models._
import com.github.aselab.activerecord.dsl._
Person.inTransaction {
// transactional code block is here
}transaction causes a new transaction to begin and commit after the block’s execution, or rollback if an exception occurs. Invoking a transaction always cause a new one to be created, even if called in the context of an existing transaction.
inTransaction will create a new transaction if none is in progress and commit it upon completion or rollback on exceptions. If a transaction already exists, it has no effect, the block will execute in the context of the existing transaction. The commit/rollback is handled in this case by the parent transaction block.