编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

Grails指南25对象关系映射高阶

wxchong 2024-06-24 20:03:37 开源技术 12 ℃ 0 评论

事件与自动时间戳

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,添加自定义约束条件

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表