Grails(Java笨狗)系列---The Application Domain
任何面向对象语言,不管是桌面,Server,Mobile 应用程序,Domain在程序中都是重要的。
Domain是任何企业应用的核心,比如在书店应用中需要Book,在购物应用中需要Order,这些企业实体相互关联着,他们的状态可以被保存,或者在以后的某个时刻被取回。
在OOP中,Object拥有属性,字段,方法。数据库中的表格拥有Columns和primary keys。如果你使用过ORM,那么对象与数据库的映射将非常的简单。
Grails是构建在Spring+Hibernate之上的,不过他提供了一种更简单的映射Grails Object-RelationalMapping (GORM)。
Grails使用Hibernate’高度定制配置APIs,考虑更加容易使用ORM映射, 通过运用规约的力量使用新的映射战略叫Grails Object-relational Mapping (GORM)。
Domain class 可以通过命令行 create-domain-class创建:
grails create-domain-class Person
他将创建一个路径为 grails-app/domain/Person.groovy 的类:
class Person { }
假如你在 DataSource设置了 dbCreate property 为 "update", "create" or "create-drop" , Grails w将自动产生修改你的数据表格。
你可以通过添加属性来定制你的Domain class:
class Person { String name Integer age Date lastVisit }
- Basic CRUD
基本的CRUD (Create/Read/Update/Delete) 操作.
Create:设置Domain属性 然后调用 save方法保存到数据库中(利用潜在的hibernate ORM层):
def p = new Person(name:"Fred", age:40, lastVisit:new Date()) p.save()
注意Groovy中new一个对象与Java中的差别,这点,会在相应的Groovy系列教材中讲到。Read:Grails 会自动添加一个 id property 在你的 domain class ,通过id来取得对应的Domain class:
def p = Person.get(1) assert 1 == p.id
Update:更新某个实体, 先设置其属性然后再次调用 save 方法:
def p = Person.get(1) p.name = "Bob" p.save()
Delete:删除实体通过 delete 方法:
def p = Person.get(1) p.delete()
Domain Modelling in GORM
下面我们来看下怎么样设计 domain in GORM.
- 创建a domain class 你可以在命令行提示符中运行 create-domain-class (必须在项目路径下使用此命令行,谨记!!!):
grails create-domain-class Book
结果一个 class 将在你的项目路径grails-app/domain/Book.groovy下被创建:class Book { }
注:假如你想创建packages,只需要把class移动到你相应的packages中,不过必须是在grails-app/domain下,然后按照Java的packages规则来声明packages。上面的Class被自动映射到一个名为book的数据表格中 (和class同样的名字,当然它是小写的).上面这些都是通过ORM Domain Specific Language规约产生的。 - 现在可以使用 Java类型来定义你的 properties
class Book { String title Date releaseDate String ISBN }
每个属性将被映射到 数据库对应表格的column中。这里有个规约:每个 column名字都是小写的,除了class的 properties使用的“驼峰”书写方式的 properties名字就需要使用“—”符号了。比如: releaseDate将被自动写成 release_date。但是你也可以通过Constraints or ORM DSL.定制。
- GORM中的关联:
One-to-one
class Face { Nose nose } class Nose { }上面,我们使用了单向one-to-one 关联从 Face 到 Nose. 如果使用双向one-to-one 关联,看下面的代码:
class Face { Nose nose } class Nose { Face face }上面两段代码都很容易理解。下面我们看下第3段代码:
class Face { Nose nose } class Nose { static belongsTo = [face:Face] }
上面我们使用了“ belongsTo ”,设置 Nose "属于" Face.
new Face(nose:new Nose()).save()
保存Face的同时,必须要保存Nose,因为这里是一个“ belongsTo ”关系,假如你使用下面的代码:
new Nose(face:new Face()).save() // will cause an error
将会产生错误。
就拿客户和订单来做比较,当然这里是使用一对一的,一个客户对应一个订单,保存客户的同时,你得把它的订单一起保存,因为这个订单是属于某个客户的,倒转过来思维,因为订单没有设置belongsTo,也就是说他不会关心他的客户是谁,可以把belongsTo这个看作是某个class的属性,如果你保存一个没有的属性当然会出错,不知道大家能不能理解,这个是我自己的意思。
继续:
def f = Face.get(1) f.delete() // both Face and Nose deleted
删除某个Faces会同时删除对应的Nose,反过来不成立。就如上面所说的,既然某个Nose是某个Face的属性,因为设置了belongsTo,我们暂时这样来理解,如果客户都不存在,订单还有存在的价值吗,其实也就是一个class被删除了,属于他的属性还会继续存在吗?