注:本文档只针对spring boot工程使用的情况有针对性的翻译,完整版本请登录GORM的github官网浏览

[[Database Mapping介绍]] == 数据库映射mapping介绍

1. Database Mapping 用法

默认情况下domain类映射到数据库的方式,使用合理的默认值.可以使用ORM Mapping DSL来定制.例如下面的`Book` domain:

And then you can use the mapping block to customize the ORM mapping behavior.

import grails.persistence.Entity;
import org.grails.datastore.gorm.GormEntity
@Entity
class Book implements GormEntity<Book>{
    String title;
    Date releaseDate;
    Author author;
    static mapping = {
        table (name:"book_table")
        comment "图书表"
        author column: "auth_id"
}

参看 GORM 了解更多.

1.1. autoImport

2. autoImport映射

2.1. 目的

在当前domain类的 HQL 查询中 Enable/disable auto import .

2.2. 示例

class Book {
    ...
    static mapping = {
        autoImport false
    }
}

2.3. 描述

Usage: autoImport(boolean)

默认情况下,domain类在HQL查询是auto-imported,因此,您不需要指定整个类名(包括包),但是,如果在不同的包中有重复的domain类名,则名称不再是唯一的,会造成`org.hibernate.DuplicateMappingException`错误。禁用其中一个或两个domain类的自动导入来修复此错误,设置`autoImport` 为 false。记住,你需要在HQL的查询中使用完全的domain类名引用。

static mapping = {
    autoImport false
}

2.3.1. autoTimestamp

3. autoTimestamp映射

3.1. 目的

设置为false时,关闭自动时间戳功能

3.2. 示例

class Book {
    ...
    static mapping = {
        autoTimestamp false
    }
}

3.3. 描述

Usage: autoTimestamp(boolean)

缺省当domain类中的属性名为 dateCreatedlastUpdated , GORM会在数据库自定维护这两个字段。可以通过设置为false关闭此功能:

static mapping = {
    autoTimestamp false
}

3.3.1. batchSize

4. batchSize映射

4.1. 目的

定制多少结果获取在懒加载执行时.

4.2. 示例

class Book {
    ...
    static mapping = {
        batchSize 10
    }
}

4.3. 描述

Usage: batchSize(integer)

针对`Author` 类拥有多个 Book`实例的延迟加载关联。GORM将执行一条查询`Author`和附加查询多条关联`Book`实例。 这就是著名的N+1问题,通常使用表连接处理,然而,关联表会消耗性能。 批量加载是针对延迟加载的一个优化方案,例如设置`batchSize`为10,并且当前作者拥有30本书. 系统将执行四次获取(一次`Author,3次批量10对象的获取),替换之前的31此获取:

static mapping = {
    batchSize 10
}

也可以在关联端设置 batchSize :

class Author {

    static hasMany = [books: Book]

    static mapping = {
        books batchSize: 10
    }
}

4.3.1. cache

5. cache映射

5.1. 目的

配置domain类支持Hibernate二级缓存.

5.2. 示例

class Book {
    ...
    static mapping = {
        cache true
    }
}

5.3. 示例

Usage: cache(boolean/string/map)

参数:

  • cache - 缓存使用. 可被设置为 read-only, read-write, nonstrict-read-writetransactional

  • include (optional) - 是否包含非延迟加载关联项。可被设置为 allnon-lazy

示例:

static mapping = {
    cache true
}

这将配置domain类使用’read-write' 缓存,需要提前确认配置的缓存政策被允许使用(缓存引擎提供支持):

static mapping = {
    cache 'transactional'
}

or

static mapping = {
    cache usage: 'read-only', include: 'non-lazy'
}

也可以在关联端设置缓存:

class Author {

    static hasMany = [books: Book]

    static mapping = {
        books cache: true // or 'read-write' etc.
    }
}

参照文档获取更多信息 Caching .

5.3.1. cascade

6. cascade映射

6.1. 目的

配置关联项的级联操作

6.2. 示例

class Author {

    static hasMany = [books: Book]

    static mapping = {
        books cascade: 'all-delete-orphan'
    }
}

6.3. 描述

Usage: association_name(cascade:string)

参数:

  • cascade - 定义级联行为. 可被设置为一个或多个 (comma-separated逗号分隔) of all, merge, save-update, delete, lock, refresh, evict, replicate or all-delete-orphan (one-to-many只支持一对多关系).

默认GORM会配置"belongs to"属性对象的级联操作为"all",示例如下:

class Book {
    static belongsTo = [author: Author]
}
class Author {
    static hasMany = [books: Book]
}

所以的持久化操作都会从`Author` 类传递到 Book 类。作者对象删除将导致关联的图书全部删除。

如果关联没有设置所有者("belongs to" 关联关系):

class Book {
}
class Author {
    static hasMany = [books: Book]
}

GORM默认使用"save-update"级联策略. 作者对象删除时,不会级联删除关联的图书。 使用`cascade`参数自定义级联行为:

class Author {

    static hasMany = [books: Book]

    static mapping = {
        books cascade: 'all-delete-orphan'
    }
}

以上配置,`Book`当成为孤儿(orphaned) 时会被删除。.

参看文档获取更多信息 transitive persistence .

6.3.1. column

7. column映射

7.1. 目的

自定义数据列的设置

7.2. 示例

static mapping = {
        currency column: "currency", sqlType: "char", length: 3
    }

7.3. 描述

Usage: property_name(map)

Arguments:

  • column - The name of the column as a String

  • sqlType (optional) - The underlying SQL type

  • enumType (optional) - The enum type in for type-safe Enum properties. Either ordinal or string.

  • index (optional) - The index name

  • unique (optional) - Whether it is unique

  • length (optional) - The length of the column

  • precision (optional) - The precision of the column

  • scale (optional) - The scale of the column

  • comment (optional) - The comment for the column (used to create the table DDL)

  • defaultValue (optional) - The database default value

By default GORM uses the property name and type to determine how to map a property in the database. For example a String property is typically mapped as a varchar(255) column. You can customize these with column configuration arguments:

static mapping = {
    currency column: "currency", sqlType: "char", length: 3
}

If you use a Hibernate type that requires multiple column definitions you can use the column method to define each column:

static mapping = {
    amount type: MonetaryUserType, {
        column name: "value"
        column name: "currency", sqlType: "char", length: 3
    }
}

Note that if you have a static method that is the same name as one of your properties you are trying to configure or you use the same property name as one of the static GORM methods this can lead to conflicts. To avoid this scenario scope the mapping configuration using the delegate property:

static mapping = {
    delegate.currency column: "currency", sqlType: "char", length: 3
}

7.3.1. comment

8. comment映射

8.1. 目的

设置生成表创建sql(DDL)时使用的注释.

8.2. 示例

class Book {
   static mapping = {
      comment "your comment here"
   }
}

8.3. 描述

Usage: comment(string)

参数:

  • comment - 具体注释

8.3.1. discriminator

9. discriminator

9.1. Purpose

Customizes the discriminator column used in table-per-hierarchy inheritance mapping. Has no effect when using table-per-subclass inheritance mapping.

9.2. Examples

class Content {
    ...
}
class PodCast extends Content {
    ...
    static mapping = {
        discriminator "audio"
    }
}

9.3. Description

Usage: discriminator(string/map)

Arguments:

  • column (optional) - The column name to store the discriminator

  • value - The value to use for the discriminator

  • formula (optional) - an SQL expression that is executed to evaluate the type of class. Use this or column but not both

  • type (optional defaults to string) - the Hibernate type, used for the where clause condition to know if it needs to wrap it with '

By default when mapping inheritance Grails uses a single-table model where all classes share the same table. A discriminator column is used to determine the type for each row, by default the full class name. You can use the discriminator method to customize what’s stored:

class Content {
    ...
}
class PodCast extends Content {
    ...
    static mapping = {
        discriminator "audio"
    }
}

You can also customize the discriminator column name:

class Content {
    ...
    static mapping = {
        discriminator column: "content_type"
    }
}
class PodCast extends Content {
    ...
    static mapping = {
        discriminator value: "audio"
    }
}

Or you can use a formula:

class Content {
    ...
    static mapping = {
        discriminator value: "1", type: "integer",
            formula: "case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end",
    }
}
class PodCast extends Content {
    ...
    static mapping = {
        discriminator value: "0"
    }
}

9.3.1. dynamicInsert

10. dynamicInsert

10.1. Purpose

Whether to dynamically build INSERT queries

10.2. Examples

class Book {

    ...
    static mapping = {
        dynamicInsert true
    }
}

10.3. Description

Usage: dynamicInsert(boolean)

By default Hibernate generates all queries at startup and caches them. This helps performance since insert, update, and delete queries don’t have to be dynamically generated at runtime. However, there are certain circumstances where dynamic queries are useful.

For example if you were using custom UserType to hash passwords, every time an UPDATE occurred, the password would get re-hashed. The dynamicInsert method lets you turn off the dynamic creation of queries that uses only the properties that are needed to perform the insert.

10.3.1. dynamicUpdate

11. dynamicUpdate

11.1. Purpose

Whether to dynamically build UPDATE queries

11.2. Examples

class Book {

    ...

    static mapping = {
        dynamicUpdate true
    }
}

11.3. Description

Usage: dynamicUpdate(boolean)

By default Hibernate generates all queries at startup and caches them. This helps performance since insert, update, and delete queries don’t have to be dynamically generated at runtime. However, there are certain circumstances where dynamic queries are useful.

For example if you were using custom UserType to hash passwords, every time an UPDATE occurred, the password would get re-hashed. The dynamicUpdate method lets you turn off the dynamic creation of queries that uses only the properties that are needed to perform the update.

11.3.1. fetch

12. fetch

12.1. Purpose

Configures the fetching behavior of an association.

12.2. Examples

class Author {

    static hasMany = [books: Book]

    static mapping = {
        books fetch: 'join'
    }
}

12.3. Description

Usage: association_name(fetch:string)

Arguments:

  • fetchStrategy - The fetching strategy to use. Either join or select.

By default GORM assumes fetching of associations is done using a SELECT when the association is accessed. If you prefer that the association be fetched eagerly at the same time then you can override the behavior:

class Author {

    static hasMany = [books: Book]

    static mapping = {
        books fetch: 'join'
    }
}

Here the books association will be fetched using a join at the same time the author is retrieved, for example:

def author = Author.get(1)
// the books collection is pre-initialized - no risk of lazy loading exceptions

Note that excessive use of joins can be a performance bottleneck. See the section on Eager vs Lazing Fetching in the user guide.

12.3.1. id

13. id

13.1. Purpose

Customizes the way the identifier for a domain class is generated

13.2. Examples

class Book {
    static mapping = {
        id generator: 'hilo',
           params: [table: 'hi_value', column: 'next_value', max_lo: 100]
    }
}

13.3. Description

Usage: id(map)

Arguments:

  • generator (optional) - The name of the generator to use. Can be increment, identity, sequence, hilo, seqhilo, uuid, guid, native, assigned, select, foreign or sequence-identity. See Hibernate reference documentation for more information.

  • composite (optional) - Takes a list of property names to use that form the composite identifier

  • name (optional) - The property name to use as the identifier

  • params (optional) - Any parameters to pass to the defined identity generator

  • column (optional) - The column name to map the identifier to. The remaining column definition properties are also available.

By default GORM uses the native strategy to generate a database identifier for each entity (typically an auto-incrementing column or a sequence). You can alter this with the id methods generator argument:

static mapping = {
    id generator: 'hilo',
       params: [table: 'hi_value', column: 'next_value', max_lo: 100]
}

You can also use the method to define a composite identifier:

static mapping = {
    id composite: ['title', 'author']
}

or change the name of the property that defines the identifier:

static mapping = {
    id name: 'title'
}

You can also alter the column definition:

static mapping = {
    id column: 'book_id', type: 'integer'
}

See the section on Custom Database Identity in the user guide for more information.

13.3.1. ignoreNotFound

14. ignoreNotFound

14.1. Purpose

Specifies how foreign keys that reference missing rows are handled in many-to-one relationships.

14.2. Examples

class LegacyCdDomain {

    String title
    Thumbnail thumbnail

    static mapping = {
        thumbnail ignoreNotFound: true
    }
}
class Thumbnail {
    byte[] data
}

14.3. Description

Usage: association_name(ignoreNotFound: boolean)

When the data in the database is corrupt and a foreign key references a non existent record, Hibernate will complain with a "No row with the given identifier exists" message. For example, a LegacyCdDomain record may have a reference to a Thumbnail record with an ID of 1234, but the database may no longer contain a Thumbnail with that ID.

One possible way to load such corrupt data is to use the ignoreNotFound mapping option. If you set it to true, Hibernate will treat a missing row as a null association. So in the above example, our LegacyCdDomain instance would load but its thumbnail property would be null. Specifying a value of false for ignoreNotFound will result in Hibernate throwing an org.hibernate.ObjectNotFoundException.

A dataset loaded with ignoreNotFound: true may throw an exception during save() because of the missing reference!

The default value for this setting is false. It maps to Hibernate’s not-found property.

This settings can be useful if you have a legacy database with unusual behaviour when it comes to referential integrity.

14.3.1. indexColumn

15. indexColumn

15.1. Purpose

Customizes the index column definition of an indexed collection such as a List or Map

15.2. Examples

class Neo {

    static hasMany = [matrix: Integer]

    static mapping = {
        matrix indexColumn: [name: "the_matrix", type: Integer]
    }
}
def neo = new Neo()
neo.matrix = [(1): 30, (2): 42, (3): 23]
neo.save(flush: true)

15.3. Description

Usage: association_name(indexColumn:map)

Arguments:

  • name - The name of the column as a String

  • type (optional) - The Hibernate type.

  • sqlType (optional) - The underlying SQL type

  • enumType (optional) - The enum type in for type-safe Enum properties. Either ordinal or string.

  • index (optional) - The index name

  • unique (optional) - Whether it is unique

  • length (optional) - The length of the column

  • precision (optional) - The precision of the column

  • scale (optional) - The scale of the column

By default when mapping an indexed collection such as a Map or List the index is stored in a column called association_name_idx which is an integer type in the case of lists and a String in the case of maps. You can alter how the index column is mapped using the indexColumn argument:

static mapping = {
    matrix indexColumn: [name: "the_matrix", type: Integer]
}

15.3.1. insertable

16. insertable

16.1. Purpose

Determines whether a property’s database column is set when a new instance is persisted.

16.2. Examples

class Book {

    String title

    static belongsTo = [author: Author]

    static mapping = {
        author insertable: false
        author updateable: false
    }
}

16.3. Description

Usage: association_name(insertable: boolean)

Useful in general where you don’t want to set an initial value (or include the column in the generated SQL) during an initial save().

In particular this is useful for one-to-many relationships. For example when you store the foreign key in the child table, it’s often efficient to save the child using only the foreign key of the parent. You do this by setting the parent object (and the parent foreign key) in the child entity. Setting the attributes insertable:false and updateable:false for the belongsTo parent object lets you insert and update using only the foreign key.

static mapping = {
    author insertable: false
}

16.3.1. joinTable

17. joinTable

17.1. Purpose

Customizes the join table used for undirectional one-to-many, many-to-many and primitive collection types.

17.2. Examples

Basic collection type:

class Book {

    static hasMany = [chapterPageCounts: Integer]

    static mapping = {
        chapterPageCounts indexColumn: [name: "chapter_number", type: Integer],
                          joinTable: [column: "page_count"]

}

Enum collection types:

enum VehicleStatus { OFF, IDLING, ACCELERATING, DECELERATING }
class Truck {

    static hasMany = [states: VehicleStatus]

    static mapping = {
        states joinTable: [name: 'VEHICLE_STATUS_LOG',
                           key: 'TRUCK_ID', column: 'STATUS']
    }
}

Many-to-many:

class Book {

    String title

    static belongsTo = Author

    static hasMany = [authors: Author]

    static mapping = {
        authors joinTable: [name: "mm_author_books", key: 'mm_book_id' ]
    }
}
class Author {

    String name

    static hasMany = [books: Book]

    static mapping = {
        books joinTable: [name: "mm_author_books", key: 'mm_author_id']
    }
}

Unidirectional One-to-many:

class Employee {

    static hasMany = [projects: Project]

    static mapping = {
        projects joinTable: [name: 'EMP_PROJ',
                             column: 'PROJECT_ID',
                             key: 'EMPLOYEE_ID']
    }
}
class Project {  }

17.3. Description

Usage: association_name(joinTable:map)

Arguments:

  • name - The table name

  • key (optional) - The foreign key

  • column (optional) - The inverse column

GORM has various strategies for mapping association types. Some of them, such as basic collection types and many-to-many associations, use a join table. You can customize how this join table is created using the joinTable argument.

17.3.1. lazy

18. lazy

18.1. Purpose

Configures whether to use proxies and lazy loading for one-to-one and many-to-one associations.

18.2. Examples

class Book {

    static belongsTo = [author: Author]

    static mapping = {
        author lazy: false
    }
}

18.3. Description

Usage: association_name(lazy: boolean)

By default GORM single-ended associations are lazy in that when you load a domain instance, an associated domain is not loaded until accessed. Hibernate creates a dynamic proxy by subclassing the domain class and proxying all methods and property access.

This can have some strange side effects (see this page on proxies at the Hibernate site) particularly in relation to inheritance. You can tell Hibernate not use proxies for single-ended associations by using the lazy argument:

static mapping = {
    author lazy: false
}

See the section on Eager vs Lazing Fetching in the user guide.

18.3.1. order

19. order

19.1. Purpose

Customizes the default sort order of query results.

19.2. Examples

class Book {
    ...
    static mapping = {
        order "desc"
    }
}

19.3. Description

Usage: order(string)

Arguments:

  • direction - Either "desc" or "asc" for descending and ascending respectively.

By defaults results are sorted in ascending order. With the order method you can alter results to be sorted in descending order. See also the sort method.

19.3.1. sort

20. sort

20.1. Purpose

Customizes the default property to sort by for query results.

20.2. Examples

class Book {
    ...
    static mapping = {
        sort "releaseDate"
    }
}

20.3. Description

Usage: sort(string/map)

By default results are sorted by creation date, and you can specify the column to order by in a query:

def results = Book.list(sort:"title")

However, you can also configure the default sort property:

static mapping = {
    sort "title"
}

in which case the sort argument is no longer needed. You can also control the sort order:

static mapping = {
    sort title: "desc" // or "asc"
}

20.3.1. table

21. table映射

21.1. 目的

自定义的domain类关联的数据库表的名称

21.2. 示例

class Book {
    static mapping = {
        table "book_catalog"
    }
}

21.3. 描述

Usage: table(string/map)

Arguments:

  • name - 表的名称

  • schema (可选) - 表的schema

  • catalog (可选) - 表的catalog

默认情况下,domain类的表的映射名字是基于类的名字。GORM将类名的java风格驼峰格式映射为表名时,使用下划线隔离。例如` productreview 成为 product_review `。你可以用`table`方法重写表名:

static mapping = {
    table "book_catalog"
}

也可以指定 schema 和 catalog名称:

static mapping = {
    table name: "book_catalog", schema: "dbo", catalog: "CRM"
}

21.3.1. type

22. type

22.1. Purpose

Configures the Hibernate type for a particular property.

22.2. Examples

Changing to a text type (CLOB or TEXT depending on database dialect):

class Book {

    String title

    static mapping = {
        title type: "text"
    }
}

User types with multiple columns:

class Book {
    ...
    MonetaryAmount amount

    static mapping = {
        amount type: MonetaryUserType, {
            column name: "value"
            column name: "currency", sqlType: "char", length: 3
        }
    }
}

22.3. Description

Usage: association_name(type:string/class)

Hibernate will attempt to automatically select the appropriate database type from the field typed based on configuration in the Dialect class that is being used. But you can override the defaults if necessary. For example String values are mapped by default to varchar(255) columns. To store larger String values you can use a text type instead:

static mapping = {
    title type: "text"
}

Hibernate also has the concept of custom UserType implementations. In this case you specify the UserType class. If the UserType maps to multiple columns you may need to specify a mapping for each column:

static mapping = {
    amount type: MonetaryUserType, {
        column name: "value"
        column name: "currency", sqlType: "char", length: 3
    }
}

22.3.1. updateable

23. updateable映射

23.1. Purpose

Determines whether a property’s database column is updated when persistent instances are updated.

23.2. Examples

class Book {

    String title

    static belongsTo = [author: Author]

    static mapping = {
        author insertable: false
        author updateable: false
    }
}

23.3. Description

Usage: association_name(updateable: boolean)

Useful in general where you don’t want to update a value (or include the column in the generated SQL) during a save().

In particular this is useful for one-to-many relationships. For example when you store the foreign key in the child table, it’s often efficient to save the child using only the foreign key of the parent. You do this by setting the parent object (and the parent foreign key) in the child entity. Setting the attributes insertable:false and updateable:false for the belongsTo parent object lets you insert and update using only the foreign key.

static mapping = {
    author updateable: false
}

23.3.1. version

24. version映射

24.1. 目的

用于禁用乐观锁定或更改保持版本的列.

24.2. 示例

class Book {
    ...
    static mapping = {
        version false
    }
}

24.3. 描述

Usage: version(string/boolean)

默认情况下,GORM配置 optimistic locking 启用. 可以通过设置 version 方法的 `false`参数来禁用:

static mapping = {
    version false
}

可以将名称传递到 `version`方法以更改数据库列的名称:

static mapping = {
    version 'revision_number'
}