Skip to main content

Naming Strategy

Naming Strategy Interface

In previous chapters, we have introduced simple entity mapping and association mapping (one-to-one, many-to-one, one-to-many, many-to-many). From these contents, we understand that

  • @Table(name = "...") can be used to explicitly specify the table name for an entity.

  • @GeneratedValue(..., sequenceName = "...") can be used to explicitly specify the sequence name required to generate the id (if using sequence generation strategy).

  • @Column(name = "...") can be used to explicitly specify the column name for ordinary columns.

  • @JoinColumn(name = "...") can be used to explicitly specify the column name for foreign key columns.

  • @JoinTable(name = "...") can be used to explicitly specify the join table name and all its column names for association properties based on join tables.

However, in order to improve development efficiency, it is impossible to use these annotations too much. In most cases, the default name deduction behavior should work, and these annotations should only be used in code in a few cases.

For a given class or property, how to automatically determine the identifier name in the database if the user does not use such annotations is called the naming strategy, which is a customizable Java interface:

package org.babyfish.jimmer.sql.meta;

import org.babyfish.jimmer.meta.ImmutableProp;
import org.babyfish.jimmer.meta.ImmutableType;

public interface DatabaseNamingStrategy {

String tableName(ImmutableType type);

String sequenceName(ImmutableType type);

String columnName(ImmutableProp prop);

String foreignKeyColumnName(ImmutableProp prop);

String middleTableName(ImmutableProp prop);

String middleTableBackRefColumnName(ImmutableProp prop);

String middleTableTargetRefColumnName(ImmutableProp prop);
}

Among them, ImmutableType and ImmutableProp are the types used by Jimmer metadata and can be intuitively understood by analogy with Class and Field in JVM reflection API.

The role of each method is:

  • tableName: Given an entity type, what is its table name?

  • sequenceName: Given an entity type whose ID growth strategy is sequence, what is its sequence name?

  • columnName: Given a non-associative property, what is its column name?

  • foreignKeyColumnName: Given an association property based on foreign key, what is its column name?

  • middleTableName: Given an association property based on join table, what is its join table name?

  • middleTableBackRefColumnName: Given an association property based on join table, what is the column name of the foreign key pointing to the current entity in the join table?

  • middleTableTargetRefColumnName: Given an association property based on join table, what is the column name of the foreign key pointing to the associated entity in the join table?

Default Naming Strategy

In most cases, developers do not need to implement this interface directly. Jimmer's built-in org.babyfish.jimmer.sql.runtime.DefaultDatabaseNamingStrategy class already implements this interface.

The DefaultDatabaseNamingStrategy class has two static fields:

  • UPPER_CASE:

    The generated database identifier names are all uppercase.

    info

    If the user does not do any configuration, this is the default naming strategy for Jimmer.

  • LOWER_CASE:

    The generated database identifier names are all lowercase.

    Some databases, such as MySQL, can be configured for case sensitivity. So it is very likely that you will be handling a MySQL database that is configured to be case sensitive with most table and column names in lowercase. In this case, you need to override the default strategy with this strategy.

tip

Even if neither UPPER_CASE nor LOWER_CASE meets your requirements and you need to implement your own strategy, you can also consider inheriting this default strategy instead of implementing from scratch.

Before introducing the behavior of the default strategy, let's first introduce a character transformation rule: snake case.

The so-called snake case refers to converting alternating case text into underscore-concatenated text, e.g. the snake case of class name BookStore is BOOK_STORE, and the snake case of property name firstName is FIRST_NAME.

Considering case issues, we define two functions u_snake and l_snake with the following behaviors:

  • u_snake("BookStore") -> "BOOK_STORE"
  • l_snake("BookStore") -> "book_store"
  • u_snake("firstName") -> "FIRST_NAME"
  • l_snake("firstName") -> "first_name"

With the conventions of u_snake and l_snake, it is easy to describe the behavior of DefaultDatabaseNamingStrategy:

note

ClassName below refers to the SimpleName of the Java class, not the QualifiedName.

UPPER_CASE

  • tableName

    Rule: u_snake(ClassName)

    Example: BookStore -> BOOK_STORE

  • sequenceName

    Rule: u_snake(ClassName)_ID_SEQ

    Example: BookStore -> BOOK_STORE_ID_SEQ

  • columnName

    Rule: u_snake(ClassName)

    Example: firstName -> FIRST_NAME

  • foreignKeyColumnName

    Rule: u_snake(ClassName)_ID

    Example: parentNode -> PARENT_NODE_ID

  • middleTableName

    Rule: u_snake(SourceClassName)_u_snake(TargetClassName)_MAPPING

    Example: Book::authors -> BOOK_AUTHOR_MAPPING

  • middleTableBackRefColumnName

    Rule: u_snake(SourceClassName)_ID

    Example: Book::authors -> BOOK_ID

  • middleTableTargetRefColumnName

    Rule: u_snake(TargetClassName)_ID

    Example: Book::authors -> AUTHOR_ID

LOWER_CASE

  • tableName

    Rule: l_snake(ClassName)

    Example: BookStore -> book_store

  • sequenceName

    Rule: l_snake(ClassName)_id_seq

    Example: BookStore -> book_store_id_seq

  • columnName

    Rule: l_snake(ClassName)

    Example: firstName -> first_name

  • foreignKeyColumnName

    Rule: l_snake(ClassName)_id

    Example: parentNode -> parent_node_id

  • middleTableName

    Rule: l_snake(SourceClassName)_l_snake(TargetClassName)_mapping

    Example: Book::authors -> book_author_mapping

  • middleTableBackRefColumnName

    Rule: l_snake(SourceClassName)_id

    Example: Book::authors -> book_id

  • middleTableTargetRefColumnName

    Rule: l_snake(TargetClassName)_id

    Example: Book::authors -> author_id

Override Strategy

Now let's demonstrate how to override the default DefaultDatabaseNamingStrategy.UPPER_CASE with DefaultDatabaseNamingStrategy.LOWER_CASE.

When using SpringBoot

@Bean
public DatabaseNamingStrategy databaseNamingStrategy() {
return DefaultDatabaseNamingStrategy.LOWER_CASE;
}

When not using SpringBoot

JSqlClient sqlClient = JSqlClient
.newBuilder()
.setDatabaseNamingStrategy(
DefaultDatabaseNamingStrategy.LOWER_CASE
)
...Omit other configurations...
.build();