Grails入门

http://www.grails.org/Scaffolding
http://www.grails.org/GORM
http://www.grails.org/Configuration#environments

Grails入门
第一章
1. 创建一个项目,使用grails create-app [你项目的名称]

2.配置数据源
在<..>/grails-app/conf目录下找到一个叫做DataSource.groory文件,他有三种标准环境Development,TestData,和production
所有的例子都是在development环境下运行。
注意:dbCreate="create-drop" one of create ,create-drop,update
可以把你需要jar包,放入到/lib目录下
dataSource{}设置的各种属性,将要被它的其他datasource继承.

3.创建一个Domian类
grails create-domain-class [类名]
注意:*命名不能是关键字
*名称的第一个字母都要大写
每个Domain类都自动成为一个持久类详见GORM

4.控制器
grails create-controller [Domian类]
class BookController {
def scaffold = Book
}
注意要移除def index={},这样scaffoldin才会正常工作
或者你可以输入
Grails generate-all 来创建所有的脚手架

5.最后运行grails run-all
注意:使用别的端口,grails-Dserver.port=9080 run-app


第二章 GORM ,Domain Class
2.1我们来详细介绍下GORM
因为Domainclass是整个应用的业务核心,他们有业务状态和行为。同时他们之间也有这1-1,n-n的关系
GORM使用的hibernate引擎
例子
def book = Book.findByTitle("Groovy in Action")book
.addToAuthors(name:"Dierk Koenig")
.addToAuthors(name:"Guillaume LaForge")
.save()

2.2Domian Class
一个domainclass本质上一个普通的Groovy类,除了在运行时候会注入"id"和"version"这两个属性

2.3关于Nullable 和 transient属性
static transients=[属性]表示这个属性永远不会写书DB,也没有相应的字段在DB中对应
static constraints = {
属性(nullable: true)
}
nullable为true允许属性的值为空

2.4默认值
String 属性='[。。。]'这样可以设置默认值


2.5改变映射的表
static mapping={
table '表的名称'
}

2.6注意属性字段名称不能是sql的保留字
比如
class Book {
Integer order
}
这个就会有问题


第三章 Domain relationShoip
3.1Domain类的关系
one to one
class Face {
Nose nose
}
class Nose {
Face face
}
当Face,saved nose也要save的
当Face删除,nose将不会删除,他们的连接是单向的

建立反转关系
class Face {
static belongsTo = Nose Nose nose
}
删除Face还是不会删除 Nose,Face只是使用Nose,而不是拥有Nose,而且要让他们产生关联必须自己去实现,比如myFace.nose = bigNose,然后bigNose.face = myFace


3.2 1-N & N -1
class Author {
static hasMany = [ books : Book ] String name
}
或者可以使用Set books=new HashSet()
class Book {
Author author
String title
}
他们的控制权是在Author,也就是One
class Author {
static hasMany = [books:Book, coBooks:Book]
static mappedBy = [books:"mainAuthor", coBooks:"coAuthor"] String name
}
static belongsTo = [Author,Publisher]
class Book {
static belongsTo = Author Author mainAuthor
Author coAuthor
String title
}

注意如果一个所有者和引用者是一个直接引用或者是潜在的hasMany关系,那么删除所有者,将会使他的引用都消失


3.3N-N
class Book {
static belongsTo = Author
static hasMany = [authors:Author]
}

class Author {
static hasMany = [books:Book]
}
在两个类中加入hasMnay关系,并至少保证一个有belongsTo属性,如果不指定将会出现error,Author是所有者,他会产生级联更新。
例子
new Author(..)
.addBook(new Book(..))
.save()
将会同时保存Author,Book.
注意删除:当你删除Author.Book你必须明确删除。
3.4
组合
在创建这种关系将不会映射到一个分开的表格,而是放在同一个表格,就是他的所有着。
class Person {
String name
Address homeAddress
Address workAddress
static embedded = ['homeAddress', 'workAddress']
}
class Address {
String houseNumber
String postCode
}

Person Table
|| id || name || homeaddresshousenumber
|| homeaddresspostcode
|| workaddresshousenumber
|| workaddresspostcode || | | | | | | | As you can see the Person class is composed to two Address classes at the domain model and database level.


第四章,IntergrationHibernate
4.1如果你更喜欢Hibernate,那么要做下面一件事情
把Hibernate.cfg.xml,Domain class,Hbm mapping放入到
%PROJECTHOME%/grails-app/conf/hibernate

4.2
使用Annotations与Hibernate映射(??有个问题,在哪里设置Setting,文档中说是configClass)
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
class DevelopmentDataSource {
def configClass = GrailsAnnotationConfiguration.class
… // remaining properties
}
environments {
development {
dataSource {
configClass = GrailsAnnotationConfiguration.class
dbCreate = "update" // one of 'create', 'create-drop','update'
//url = "jdbc:hsqldb:mem:devDB"
url = "jdbc:postgresql://localhost/vprocedure"
}
} ....

让我们创建一个annotated对象来在使用在grails-app/domain下


package com.books;
@Entity
public class Book {
private Long id;
private String title;
private String description;
private Date date; @Id
@GeneratedValue
public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public String getDescription() {
return description;
} public void setDescription(String description) {
this.description = description;
}
}
我们需要你用HibernateSessionFactory注册一个Class,我们/Grails-app/conf/hibernate/hibernate.cfg.xml文件中添加
<!DOCTYPE hibernate-configuration SYSTEM
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping package="com.books" />
<mapping class="com.books.Book" />
</session-factory>
</hibernate-configuration>

注意:我们已经可以使用Book的动态方法,他是scaffolding提供的。
Note when you generate views or controllers you need to specify the entire package name, i.e. com.books.Book, as there are currently (v 0.3) mistakes in the generated code. Specifically, the static methods need to be fully qualified (add the package name).


第五章Set,List,Map,inheritance
Sets, Lists & Maps
Sets of objects
By default when you define a relationship with GORM it is a java.util.Set which is an unordered collection that cannot contain duplicates. In other words when you have:
class Author {
static hasMany = [books:Book]
}
The {{books}} property that GORM injects is a java.util.Set. The problem with this is there is no ordering when accessing the collection, which may not be what you want. To get custom ordering you can say that the set is a SortedSet:
code: null

class Author {
SortedSet books
static hasMany = books:Book
}
code: null

In this case a java.util.SortedSet implementation is used which means you have to implement java.lang.Comparable in your Book class:
code: null

class Book implements Comparable {
String title
Date releaseDate = new Date()
int compareTo(obj) {
releaseDate.compareTo(obj.releaseDate)
}
}
code: null

The result of the above class is that the Book instances in the {{books}} collections of the Author class will be ordered by their release date.
Lists of objects (Since 0.5)
If you simply want to be able to keep objects in the order which they were added and to be able to reference them by index like an array you can define your collection type as a List:
class Author {
List books
static hasMany = [books:Book]
}

In this case when you add new elements to the {{books}} collection the order is retained in a sequential list indexed from 0 so you can do:
author.books[0] // get the first book

The way this works at the database level is Hibernate creates a books_idx column where it saves the index of the elements in the collection in order to retain this order at the db level.
Note When using a list, elements must be added to the collection before being saved, otherwise Hibernate will throw an exception ({{org.hibernate.HibernateException: null index column for collection}}):
// This won't work!
def book = new Book(title: 'The Shining')
book.save()
author.addToBooks(book)
// Do it this way instead.
def book = new Book(title: 'Misery')
author.addToBooks(book)
author.save()
Maps of objects (Since 0.5)
If you want a simple map of string/value pairs GORM can map this with the following:
class Author {
Map books // my of ISBN:book names
}
def a = new Author()
a.books = ["1590597583":"Grails Book"]
a.save()

In this case the key and value of the map MUST be strings.
If you want a Map of objects then you can do this:
class Book {
Map authors
static hasMany = [authors:Author]
}
def a = new Author(name:"Stephen King")
def book = new Book()
book.authors = ["stephen":a]
book.save()

The static hasMany property defines the type of the elements within the Map. The keys for the map MUST be strings.

Mapping Inheritance
By default, GORM uses table-per-hierarchy inheritance, which essentially means the parent and all sub-classes share the same table:
class Content {
String author
}
class BlogEntry extends Content {
URL url
}
class Book extends Content {
String ISBN
}
class PodCast extends Content {
byte[] audioStream
}
The above then allows you to perform polymorphic queries:
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".
As an alternative, you can tell GORM to use a joined-subclass model to implement inheritance.
class Content {
static mapping = {
tablePerHierarchy false
}
String author
}
Technical note for those interested: This will use 4 tables (Content, BlogEntry, Book, and PodCast) with each subclass table containing only those fields unique to it, e.g., Book would contain an ISBN column, but not an audioStream column.


第六章 CRUD
CRUD Operations
Grails domain classes use dynamic persistent methods to facilitate CRUD (Create/Read/Update/Delete) operations on persistent classes:
CREATE
To create entries in the database, domain class instances support a "save" method which cascades to the instance relationships. In the example below we only call "save" on the author and both the Author and Book instances are persisted:
def a = new Author(name:"Stephen King")
def b = new Book(title:"The Shining",author:a)
a.books.add(b)
// persist
a.save()


In this case we're having to create both sides of the relationship manually. GORM will manage the persistence of your object model to the database, but won't manage the relationships for you.
However since 0.3 Grails provides more intelligent relationship management that will manage bidrectional relationship state through dynamic methods:
def a = new Author(name:"Stephen King")
.addBook( new Book(title:"The Shining") )
.addBook( new Book(title:"The Stand") )


This will add several books to the Author plus make sure the author property on each Book is set thus managing this burden for you.
READ
Grails supports a number of ways of retrieving domain class instances, for more detail on querying see the section on  Domain Class Querying, however to retrieve an instance if the "id" is known you can use the "get" static method:
Book.get(1)


Or to find all books the "findAll", "list" or "listOrderByX" static methods can be used:
Book.findAll() // retrieve all
Book.list(max:10) // lists first 10 instances
Book.listOrderByTitle() // lists all the instances ordered by the "title" property


UPDATE
The semantics of updating differ from that of saving a domain class. It is possible to update without explicitly calling "save" with the changes automatically being persisted if no exceptions occur:
def b = Book.get(1)
b.releaseDate = new Date()


This behaviour is not always desired however paricularily when combined with validation constraints (ie you don't want your domain object saved if it is not validated). Therefore if you explicity call "save" and the object is not valid changes will not be persisted:
def b = Book.get(1)
b.title = null // can't have a null title
b.save() // won't save as fails to validate


It is sometimes handy though to make changes to your domain model programmatically if validation fails. In this way the semantics of the "validate" method differ as it won't discard the changes if validation fails:
def b = Book.get(1)
b.publisher = "Print It"
if(!b.validate()) {
b.publisher = Publisher.DEFAULT
}


In the above case changes will still be persisted even though validation failed during the "validate" method. If you want the "validate" method to not persist changes if it fails to validate you can pass a boolean "true" argument:
b.validate(true)


Alternatively, if you want to explicitly control if changes are persisted you can use the "discard" method that when called will discard any changes:
def b = Book.get(1)
b.title = "A New Title"
// something happenedd to change your mind
b.discard()


DELETE
Domain class instances can be removed from the database by using the "delete" instance method:
def b = Book.get(1)
b.delete()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值