欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

GORM翻译

程序员文章站 2022-03-14 13:48:50
...
第一次翻译,翻译的不好,希望大牛们可以校正,说实话grails关注的人实在太少,哎,现在弄的缺乏信心了.

Grails : GORM
Grails Object Relational Mapping (GORM)
介绍
域对象是任何商业应用的核心. 这些对象保持商业过程的状态同样也实现行为. 他们通过one-to-one或者one-to-many等关系相互连接起来.
GORM是Grails对象关系映射(ORM) 的实现. 他使用Hibernate 3 引擎(一个非常流行和灵活的开源ORM 解决方法),GORM同时支持动态和静态的域对象创建,在缺省情况下,Grails采用动态的域对象创建,这样可以不用写hibernate的配置文件.
你同样可以使用Java写一个Grails的域对象,[参见 Hibernate Integration 这里介绍了怎样用java写一个grails域对象但是仍然可以使用域对象的动态方法]
创建一个域对象
Grails中一个域对象从本质上来说是一个带有id和version属性的Groovy类.
Book.groovy
class Book {
    Long id
    Long version

    String title
}
你可以在你的Grails项目的根目录下面使用如下命令快捷的创建一个域对象定义:
grails create-domain-class
创建关系
定义一个一对多的关系就是简单的定义一个Set类型的属性,然后把属性加入到” relatesToMany”这个map中:
Author.groovy
class Author {
    Long id
    Long version

    def relatesToMany = [ books : Book ]

    String name
    Set books = new HashSet()
}
Groovy一个主要的特性是他支持静态键入,这就意味这我们不需要把one-to-one, many-to-one关联放入relationships这个map中:
Book.groovy
class Book {
    Long id
    Long version

    Author author
    String title
}
one-to-many拥有者就是定为one的这一端 (在上面的例子中是 "Author.groovy"), 但如果你创建了一个one-to-one的映射,那么定义这个关联关系的拥有者就非常重要了. 例如如果我们有一个Author类,它没有和Book定义关联关系, (ie in a one-to-one scenario), 那么Grails会假定Book是Author的拥有者.实际上这是非常严重的错误. 因为这意味着当你删除一个Book实例的时候,这个删除操作同样会去删除该实例对应的Author,因为拥有者是Book而不是Author.这不是我们要得到的结果.
因此我们必需在one-to-one或者many-to-one这样的关系中定义一个被拥有这样的属性. 在Grails中我们在被拥有者这一端定义一个"belongsTo" 属性:
Book.groovy
class Book {
    Long id
    Long version

    def belongsTo = Author

    Author author
    String title
}
如下,一个域对象可以同时被多个对象拥有:
@Property belongsTo = [Author,Publisher]
换句话说:
• 一个拥有者能够拥有其他域对象
• 被拥有这使用'belongsTo' 属性指向他的拥有者
• 如果一个拥有者被删除了,所有属于他的被拥有者也将消失
关系概要
下面这个表格定义了两个类A和B之间可能的关联关系
关系可能是单向的 (->) 或者双向的(<->),也拥有关系的类型one-to-one (1:1), one-to-many (1:m), many-to-one (m:1), and many-to-many (n:m).
拥有者的字体是粗体.
A:B 单向 双向
1:1 A -> B A <-> B ; B.belongsTo = [A]
1:m A -> Set ; A.relatesToMany= [B] A -> Set ; A.relatesToMany = [B]; B -> A 

m:1 A -> B A -> B ; B -> Set ; B.relatesToMany = [A] 

n:m Grails中未实现 Grails中未实现
在one-to-many中如果one这端是拥有者的话那么,不需要belongsTo 定义
opposite of 
映射继承
GORM使用 table-per-heirarchy 继承,从本质上来说父对象和所有子对象共享共用一张表:
class Content {
     Long id
     Long version

     String author
}
class BlogEntry extends Content {
    URL url
}
class Book extends Content {
    String ISBN
}
class PodCast extends Content {
    byte[] audioStream
}
上面的定义允许你运行多态查询:
def content = Content.findAll() // find all blog entries, books and pod casts
content = Content.findAllByAuthor('Joe Bloggs') // find all by author

def podCasts = PodCast.findAll() // find only pod casts

Technical note for those interested: Under the covers, only one table is used in the table-per-hierarchy model. A class column specifies the subclass and any fields in the subclasses are included on the same table. Subclass fields cannot be "required" because the underlying columns need to be nullable for the other subclasses. This doesn't however prevent you from using Validation constraints to ensure that subclass fields are "required".
技术提示:在继承关系中所有对象只有一张表,所有父类属性和子类属性都放在这张表里面,子类的属性不能是”require”因为他有可能在其他子类中是可以为空的,但是这并不妨碍你对子类的字段使用校验条件”constraints”使用required条件
Optional(可选的) 和Transient(瞬时的)属性
在缺省情况下,所有的属性都是persistent(可持久化) 和required(必需的),你可以使用名为”optionals”(可选的)和”transients”(瞬时的)类型为List属性来改变他:
Book.groovy
class Book {
    Long id
    Long version

    def optionals = [ "releaseDate" ]
    def transients = [ "digitalCopy" ]

    Author author
    String title
    String author
    Date releaseDate
    File digitalCopy
}
CRUD 操作
Grails域对象使用动态的持久化方法容易的在域对象上进行CRUD (Create/Read/Update/Delete)操作:
Create
为了在数据库中创建一个域对象的实例,域对象可以使用save方法,save方法可以把关系中的其他对象也级联保存. 在下面这个例子中,我们仅仅调用一个author的”save”方法,那么Author和Book实例都将存储到数据库中:
def a = new Author(name:"Stephen King")
def b = new Book(title:"The Shining",author:b)
a.books.add(b)

// persist
a.save()
注意:在通常情况下,推荐使用在你的域对象中添加一个方法管理域对象关系,而不是象上面那样直接加入一个实例到”books”这个Set中.例如下面的例子中就添加了一个addBook方法:
def addBook(book) {
   if(!books)books = new HashSet()
   book.author = this
   books.add(book)
   return this
}
GORM 将会管理你的域对象数据存储到数据库, 但是不会自动为你管理对象之间的关系的优化.因此代码将变成:
def a = new Author(name:"Stephen King")
a.addBook(new Book(title:"The Shining"))
.addBook(new Book(title:"IT"))
.save()
Read
Grails中有很多中方式得到域对象实例, 更多的信息可以参见 Domain Class Querying, 然而如果我们知道域对象实例的id属性,那么我们可以用get静态方法来得到:
Book.get(1)
或者使用 "findAll", "list" 或 "listOrderByX" 来获取多个对象:
Book.findAll() // retrieve all
   Book.list(10) // lists first 10 instances
   Book.listOrderByTitle() // lists all the instances ordered by the "title" property
Update
更新一个域对象实例和save方法不同,  他可能不会明确调用save方法来保存. 如果没有异常发生,那么对象所做的修改将会被自动保存到数据库[但是这个对象必需是从数据库获取的,否则必需显式调用save,因为在调用save的时候,如果数据库里没有这个对象,会多执行一跳sql语句获取对象的主键]:
def b = Book.get(1)
b.releaseDate = new Date()
这种行为可能不是一直是我们所希望,特别是当我们和validation条件结合的情况下, (可能你不希望你的域对象实例没有经过检验就存到数据库中.因此当你直接调用save方法的时候,如果对象不符合检验条件,那么他将不会被存入数据库:
def b = Book.get(1)
b.title = null // can't have a null title
b.save() // won't save as fails to validate
有时,我们可能需要在校验失败的时候仍然保存对象到数据库,那么我们可以显式调用validate方法来校验:
def b = Book.get(1)
b.publisher = "Print It"

if(!b.validate()) {
   b.publisher = Publisher.DEFAULT
}
在上面的例子中,对象在校验失败的时候仍然保存到数据库. 如果你希望validate方法在校验失败的时候不存入数据库,你可以使用validate(true):
b.validate(true)
可选的是,如果你向明确控制对象的持久化(保存到数据库)你可以使用discard方法,他将会把对象从持久化框架中剔除,从而不把对象修改保存到数据库中:
def b = Book.get(1)
b.title = "A New Title"

// something happenedd to change your mind
b.discard()
Delete
域对象实例能使用delete方法从数据库中删除掉:
def b = Book.get(1)
b.delete()
域对象查询
使用动态方法查询
Grails有很多种方法通过动态方法查询域对象的实例, 详细的情况参考 DomainClass Dynamic Methods:
def results = Book.findByTitle("The Stand")

results = Book.findByTitleLike("Harry Pot%")
results = Book.findByReleaseDateBetween( firstDate, secondDate )
results = Book.findByReleaseDateGreaterThan( someDate )
results = Book.findByTitleLikeOrReleaseDateLessThan( "%Something%", someDate )

// find by relationship
results = Book.findAllByAuthor( Author.get(1) )
使用实例查询
你可以使用find方法查询域对象仅仅通过传递一个域对象实例.
def b = Book.find( new Book(title:'The Shining') )
使用criteria builder查询(criteria builder是hibernate架构的一种便捷查询方式)
对于高级的查询或者域对象交叉查询可以使用Criteria (详见 Builders):
def c = Book.createCriteria()
def results = c {
     like("author.name", "Stephen%")
     between("releaseDate", firstDate, secondDate )
}
使用HQL语言查询(HQL:Hibernate Query Language[hibernate查询语言])
另外,可以使用hibernate本身的查询语言HQL:
def results = Book.find("from Book as b where b.title like 'Lord of the%'")
或者带有参数:
def results = Book.find("from Book as b where b.title like ?", ["The Shi%"])


Document generated by Confluence on Jul 14, 2006 09:01