事件与自动时间戳
beforeInsert - 对象持久化到数据库之前执行,如果返回false,添加过程将取消
beforeUpdate - 对象更新之前执行,如果返回false,更新过程将取消
beforeDelete - 对象删除之前执行,如果返回false,删除过程将取消
beforeValidate - 在对象验证之前执行
afterInsert - 对象被持久化到数据库后执行
afterUpdate - 对象被更新之后执行
afterDelete - 对象被删除之后执行
onLoad - 对象从数据库中获取之时执行
afterLoad - 对象从数据库中获取之后执行
注意:不要在Domain模型的事件中立即持久化flush保存数据,如obj.save(flush:true)。因为这会可能导致循环嵌套的出现,最终以StackOverflowError错误收场。
##################
beforeInsert事件
class Person {
private static final Date NULL_DATE = new Date(0)
String firstName
String lastName
Date signupDate = NULL_DATE
def beforeInsert() {
if (signupDate == NULL_DATE) {
signupDate = new Date()
}
}
}
beforeUpdate事件
class Person {
def securityService
String firstName
String lastName
String lastUpdatedBy
static constraints = {
lastUpdatedBy nullable: true
}
def beforeUpdate() {
lastUpdatedBy = securityService.currentAuthenticatedUsername()
}
}
beforeDelete事件
class Person {
String name
def beforeDelete() {
ActivityTrace.withNewSession {
new ActivityTrace(eventName: "Person Deleted", data: name).save()
}
}
}
beforeValidate事件
class Person {
String name
static constraints = {
name size: 5..45
}
def beforeValidate() {
name = name?.trim()
}
}
beforeValidate事件增强
class Person {
String name
String town
Integer age
static constraints = {
name size: 5..45
age range: 4..99
}
def beforeValidate(List propertiesBeingValidated) {
// do pre validation work based on propertiesBeingValidated
}
}
def p = new Person(name: 'Jacob Brown', age: 10)
p.validate(['age', 'name'])
onLoad事件
class Person {
String name
Date dateCreated
Date lastUpdated
def onLoad() {
log.debug "Loading ${id}"
}
}
afterLoad事件
class Person {
String name
Date dateCreated
Date lastUpdated
def afterLoad() {
name = "I'm loaded"
}
}
####################
自动时间戳
如果你定义了dateCreated属性,当你创建新实例时,dateCreated将被自动设置为当前日期。同样,如果你定义了lastUpdated属性,当你更新实例时,lastUpdated将被自动更新为当前日期(即修改日期)。
class Person {
Date dateCreatedd
Date lastUpdated
static mapping = {
autoTimestamp true //false关闭自动时间戳,true开启自动时间戳,默认是开启状态true
}
}
注意:dateCreated与lastUpdated的约束不能设置为nullable: false,否则会验证失败。应省略字段约束,或设置为nullable: true
####################
自定义ORM映射
class Person {
...
static mapping = {
version false //关闭版本信息
autoTimestamp false //关闭自动时间戳
}
}
你也可以定义全局映射,在application.groovy中:
grails.gorm.default.mapping = {
version false
autoTimestamp false
}
####################
表名及列名映射
class Person {
...
static mapping = {
table 'people'
}
}
class Person {
String firstName
static mapping = {
table 'people' //表名映射
firstName column: 'First_Name' //列名映射
}
}
class Address {
String number
String postCode
static mapping = {
postCode type: 'text' //字段类型映射
}
}
映射举例1:
class Person {
String firstName
Address address
static mapping = {
table 'people'
firstName column: 'First_Name'
address column: 'Person_Address_Id' //默认为address_id,现指定为Person_Address_Id
}
}
映射举例2:
class Group {
...
static hasMany = [people: Person]
}
class Person {
...
static belongsTo = Group
static hasMany = [groups: Group]
}
只进行字段映射
class Group {
...
static mapping = {
people column: 'Group_Person_Id'
}
}
class Person {
...
static mapping = {
groups column: 'Group_Group_Id'
}
}
只进行表名映射
class Group {
...
static mapping = {
people joinTable: 'PERSON_GROUP_ASSOCIATIONS'
}
}
class Person {
...
static mapping = {
groups joinTable: 'PERSON_GROUP_ASSOCIATIONS'
}
}
进行字段与表名映射
class Group {
...
static mapping = {
people column: 'Group_Person_Id', joinTable: 'PERSON_GROUP_ASSOCIATIONS' //Group_Person_Id命名与关联可能存在逻辑问题,请注意
}
}
class Person {
...
static mapping = {
groups column: 'Group_Group_Id', joinTable: 'PERSON_GROUP_ASSOCIATIONS' //Group_Group_Id命名与关联可能存在逻辑问题,请注意
}
}
####################
缓存
class Person {
...
static mapping = {
table 'people'
cache true
}
}
class Person {
...
static mapping = {
table 'people'
cache usage: 'read-only', include: 'non-lazy' //'read-write' or 'read-only' or 'transactional' or 'nonstrict-read-write'
}
}
class Person {
String firstName
static hasMany = [addresses: Address]
static mapping = {
table 'people'
version false
addresses column: 'Address', cache: true
}
}
class Address {
String number
String postCode
}
####################
def person = Person.findByFirstName("Fred", [cache: true])
def people = Person.withCriteria {
like('firstName', 'Fr%')
cache true
}
####################
定制ID
class Person {
...
static mapping = {
table 'people'
version false
id column: 'person_id'
}
}
####################
import org.apache.commons.lang.builder.HashCodeBuilder
class Person implements Serializable {
String firstName
String lastName
boolean equals(other) {
if (!(other instanceof Person)) {
return false
}
other.firstName == firstName && other.lastName == lastName
}
int hashCode() {
def builder = new HashCodeBuilder()
builder.append firstName
builder.append lastName
builder.toHashCode()
}
static mapping = {
id composite: ['firstName', 'lastName']
}
}
####################
class Address {
Person person
}
class Person {
String firstName
String address
static mapping = {
table 'people'
version false
id column: 'person_id'
firstName column: 'First_Name', index: 'Name_Idx'
address column: 'Address', index: 'Name_Idx,Address_Index'
}
}
class Person {
String firstName
Pet pet
static hasMany = [addresses: Address]
static mapping = {
addresses lazy: false
pet fetch: 'join'
}
}
class Address {
String street
String postCode
}
class Pet {
String name
}
class Person {
String firstName
Pet pet
static mapping = {
pet batchSize: 5
}
}
####################
衍生属性使用举例:
class Product {
Float price
Float taxRate
Float tax
static mapping = {
price column: 'PRICE'
taxRate column: 'TAX_RATE'
tax formula: 'PRICE * TAX_RATE'
}
}
Product.findAllByTaxGreaterThan(21.12)
Product.withCriteria {
gt 'tax', 21.12f
}
####################
默认排序:
def airports = Airport.list(sort:'name') //使用list方法加参数
class Airport {
...
static mapping = {
sort "name" //在模型中进行声明
}
}
class Airport {
...
static mapping = {
sort name: "desc" //自定义排序策略,升序asc或降序desc
}
}
class Airport {
...
static hasMany = [flights: Flight]
static mapping = {
flights sort: 'number', order: 'desc' //关联排序
}
}
注意:排序设置,在单向一对多或多对多关系中,会失效。
########################
事务编程:
def transferFunds() {
Account.withTransaction { status ->
def source = Account.get(params.from)
def dest = Account.get(params.to)
def amount = params.amount.toInteger()
if (source.active) {
if (dest.active) {
source.balance -= amount
dest.amount += amount
}
else {
status.setRollbackOnly()
}
}
}
} //银行转账,钱的减少与钱的增加不可分割,即一个事务,如中途出错,事务回滚,回到初始状态
###################
约束constraints
class User {
String login
String password
String email
Integer age
static constraints = {
login size: 5..15, blank: false, unique: true
password size: 5..15, blank: false
email email: true, blank: false
age min: 18
}
}
约束参考:
约束,描述,举例
blank,值不能为空,login(blank:false)
creditCard,值是有效的信用卡号,cardNumber(creditCard: true)
email,值是有效地邮箱地址,homeEmail(email: true)
inList,值要在列表内存在,name(inList: ["Joe"])
matches,值要与正则匹配,login(matches: "[a-zA-Z]+")
max,值不能超过给定的最大值,age(max: new Date()) price(max: 999F)
maxSize,值的规模不能超过给定的大小,children(maxSize: 25)
min,值不能超过给定的最小值,age(min: new Date()) price(min: 0F)
minSize,值的规模不能小于给定的大小,children(minSize: 25)
notEqual,不等于,login(notEqual: "Bob")
nullable,不能为null,age(nullable: true)
range,值要在给定满为内,age(range: 18..65)
scale,保留小数位数,salary(scale: 2)
size,值规模的范围,children(size: 5..15)
unique,不可重复,login(unique: true)
url,值要是一个有效的URL,homePage(url: true)
validator,添加自定义约束条件
本文暂时没有评论,来添加一个吧(●'◡'●)