Grails的数据库相关开发

AllenYoung 2013-11-18

1.开发domain和service

在出来的输入框里输入domain的名字,可以包括包名。

这里我输入test.domain.House,点finish

创建了两个groovy文件,一个当然是test.domain.House.groovy,另一个是test.domain.HouseTests.groovy.

先说test.domain.House.groovy。这个就是传说中的POGO。Grails会在运行时给他注入很多方法。

现在给他增加两个属性:

Groovy代码收藏代码

packagetest.domain

classHouse{

Stringname

Stringaddress

staticconstraints={

}

}

新建一个service(方法参见上一篇),名称可以直接输入House的类全名。

编辑生成的service单元测试:

Groovy代码收藏代码

packagetest.domain

importgrails.test.mixin.*

importorg.junit.*

/**

*SeetheAPIfor{@linkgrails.test.mixin.services.ServiceUnitTestMixin}forusageinstructions

*/

@TestFor(HouseService)

@Mock(House)

classHouseServiceTests{

voidtestFindByAddress(){

newHouse(name:"BeautifulHouse",address:"No.1").save();

defhouse=service.findByAddress("No.1")

asserthouse!=null

printlnhouse.id

}

}

注意这一行:

printlnhouse.id

之前并没有给House定义ID,GORM会默认给他加上一个ID。

另外说一下@Mock(House)。因为domain要在grails运行时才会给domain注入方法,如果在单元测试的时候可以使用Mock这个annotation,给House这个domain注入运行时的模拟方法。

实现一下service:

Groovy代码收藏代码

packagetest.domain

classHouseService{

deffindByAddress(Stringaddress){

returnHouse.findByAddress(address)

}

}

findByAddress就是一个动态生成的方法,可以让我们按地址查找。

运行一下HouseServiceTests这个单元测试:

当然也可以先debug,跑完以后会弹出打开TESTS-TestSuites.xml这个文件。点下面的sheet切换:

就可以看到test里打的println了:

<system-out><![CDATA[--OutputfromtestFindByAddress--

1

]]></system-out>

这个XML的格式不解释。

service需要加事务吧:

Groovy代码收藏代码

packagetest.domain

importorg.springframework.transaction.annotation.Transactional;

classHouseService{

@Transactional(readOnly=true)

deffindByAddress(Stringaddress){

returnHouse.findByAddress(address)

}

}

依然可以使用spring的@Transactional。当然也有别的方法。暂时不写了。

2.domain的验证

test.domain.HouseTests.groovy不明白为什么要生成这个测试单元。方法都是Grails注入的,MS没什么好测的。

现在拿来做测试验证吧。

给test.domain.House.groovy加多几个属性:

Groovy代码收藏代码

packagetest.domain

classHouse{

Stringname

Stringtype

Stringdesc

Stringaddress

DatebuildedDate

Floatprice;

staticconstraints={

typeinList:["common","bungalow","villa"],nullable:true

descmaxSize:1000,nullable:true

buildedDatemax:newDate(),nullable:true

pricemax:98765432109876543210f,scale:2,nullable:true

}

}

重点看下边的constraints。这里定义属性的约束,选了几个典型的。

inList,适用于枚举。

desc这种属于大文本,字符串默认在数据库里会变成varchar(255),定义了最大值就会成为TEXT

bulidedDate这种属于历史时间,不应当晚于当前时间。参照这种定义方法。

price属于浮点,定义最大最小值的时候需要注意要是浮点数(注意最后的f),默认的scale是3

测试代码如下:

Groovy代码收藏代码

packagetest.domain

importgrails.test.mixin.*

importgrails.test.mixin.domain.DomainClassUnitTestMixin;

importorg.junit.*

/**

*SeetheAPIfor{@linkgrails.test.mixin.domain.DomainClassUnitTestMixin}forusageinstructions

*/

@TestFor(House)

classHouseTests{

voidtestSomething(){

mockForConstraintsTests(House)

defhouse=newHouse(name:"House1",type:"unknown");

assert!house.validate()

printlnhouse.errors["type"]

}

}

mockForConstraintsTests(House)是内置的给domain加上验证框架的内置方法的一个mock。house.validate()用于验证所有定义的约束,可以用在web和service里,house.errors["属性名"]可以查违反的约束。

运行测试可以看到结果。

3.domain间的关系

关于一对一,多对对,一对多,多对一的这些个关系,官方的reference写得挺清楚,不翻译了。

不过得注意一下这个belongsTo

如让房子有个主人:

Groovy代码收藏代码

packagetest.domain

classHouse{

Stringname

Stringtype

Stringdesc

Stringaddress

DatebuildedDate

Floatprice;

staticbelongsTo=[owner:Person]

staticconstraints={

typeinList:["common","bungalow","villa"],nullable:true

descmaxSize:1000,nullable:true

buildedDatemax:newDate(),nullable:true

pricemax:98765432109876543210f,scale:2,nullable:true

}

}

packagetest.domain

Groovy代码收藏代码

classPerson{

Stringname

statichasMany=[houses:House]

staticconstraints={

}

}

这时房子从属于人,当人删除的时候会对房子造成级联删除。有一定危险,使用的时候要注意。

由于不知道怎么在单元测试里检验下面要说的东西所以……

以下内容属于道听未经验证

4.多数据源

假设第二个数据源叫datasoruce_second,配置如下

Groovy代码收藏代码

environments{

development{

dataSource{

dbCreate="create-drop"

url="jdbc:h2:mem:devDb"

}

dataSource_second{

dialect=org.hibernate.dialect.MySQLInnoDBDialect

driverClassName='com.mysql.jdbc.Driver'

username='root'

password='root'

url='jdbc:mysql://localhost/root'

dbCreate='update'

}

}

test{

dataSource{

dbCreate="update"

url="jdbc:h2:mem:testDb"

}

}

production{

dataSource{

dbCreate="update"

url="jdbc:h2:prodDb"

}

dataSource_second{

dialect=org.hibernate.dialect.Oracle10gDialect

driverClassName='oracle.jdbc.driver.OracleDriver'

username='root'

password='root'

url='jdbc:oracle:thin:@localhost:1521:root'

dbCreate='update'

}

}

}

如果人这个表用的这个数据源:

Groovy代码收藏代码

packagetest.domain

classPerson{

Stringname

statichasMany=[houses:House]

staticconstraints={

datasources(["second"])

}

}

另外还可以引入别的datasource的包,把数据源当成spring的bean注入到程序里使用。

5.直接执行SQL

一种方法当然是写java代码,然后groovy当bean来调用,这种感觉用groovy用得比较假。。。

直接写SQL的形如:

Groovy代码收藏代码

packagetest.sql

importgroovy.sql.Sql

classSQLTestService{

defdataSource

defsqlRun(){

defdb=newSql(dataSource)

db.eachRow('select*fromhouse'){

printlnit

}

}

}

以上两节留待以后验证

相关推荐