Skip to main content

Real and Fake Foreign Keys

Through the discussion of Association Mapping, we know that association mapping requires a lot of foreign keys.

There are two types of foreign keys in Jimmer:

  • Real foreign key:

    There is a corresponding foreign key constraint in the database.

  • Fake foreign key:

    It is a foreign key in the developer's mind, but there is no corresponding foreign key constraint in the database.

info

When saving data:

  • Real foreign keys rely on the ability of relational databases themselves to ensure referential integrity.

  • Fake foreign keys rely on additional checks inserted by the ORM in the upper layer code to ensure referential integrity.

This difference is transparent to the user. The user only needs to configure the authenticity of the foreign key without modifying the business code.

Explicitly specify real foreign key

  • Association property based on foreign key

    Book.java
    @Entity
    public interface Book {

    @ManyToOne
    @JoinColumn(foreignKeyType = ForeignKeyType.REAL)
    BookStore store();

    ...Omit other code...
    }
  • Association property based on join table

    Book.java
    @Entity
    public interface Book {

    @ManyToMany
    @JoinTable(
    joinColumns = {@JoinColumn(foreignKeyType = ForeignKeyType.REAL)},
    inverseJoinColumns = {@JoinColumn(foreignKeyType = ForeignKeyType.REAL)}
    )
    List<Author> authors();

    ...Omit other code...
    }
    info

    Different from previous examples:

    • Configure JoinTable.joinColumns instead of JoinTable.joinColumnName

      If the foreign key has only one column and the authenticity does not need to be explicitly specified, joinColumnName is a simplified configuration. Otherwise, joinColumns should be used.

    • Configure JoinTable.inverseJoinColumns instead of JoinTable.inverseJoinColumnName

      If the foreign key has only one column and the authenticity does not need to be explicitly specified, inverseJoinColumnName is a simplified configuration. Otherwise, inverseJoinColumns should be used.

caution

If the database dialect does not support foreign keys (e.g. org.babyfish.jimmer.sql.dialect.TiDBDialect), real foreign keys cannot be explicitly specified.

This is because TiDB, as a distributed relational database, does not support foreign key constraints.

Explicitly specify fake foreign key

  • Association property based on foreign key

    Book.java
    @Entity
    public interface Book {

    @ManyToOne
    @Nullable
    @JoinColumn(foreignKeyType = ForeignKeyType.FAKE)
    BookStore store();

    ...Omit other code...
    }
  • Association property based on join table

    Book.java
    @Entity
    public interface Book {

    @ManyToMany
    @JoinTable(
    joinColumns = @JoinColumn(foreignKeyType = ForeignKeyType.FAKE),
    inverseJoinColumns = @JoinColumn(foreignKeyType = ForeignKeyType.FAKE)
    )
    List<Author> authors();

    ...Omit other code...
    }

Do not explicitly specify the authenticity of foreign keys

To avoid explicitly specifying the authenticity of foreign keys, use @JoinColumn(foreignKeyType = ForeignKeyType.AUTO).

Since ForeignKeyType.AUTO is the default configuration for the @JoinColumn annotation, an even better choice is to make no configuration at all.

Therefore, the code is no different from the sample code in Association Mapping, so there is no need for sample code here.

If the authenticity of the foreign key is not explicitly specified, whether the foreign key is real or fake is automatically determined by the following two steps:

  1. If the database dialect does not support foreign keys (e.g. org.babyfish.jimmer.sql.dialect.TiDBDialect), it is determined to be a fake foreign key.

    At this point, the judgment is completed and it returns early without executing step 2.

  2. If step 1 cannot complete the determination, check Jimmer's global configuration foreign-key-enabled-by-default.

    If this configuration is true, it is determined to be a real foreign key; otherwise, it is determined to be a fake foreign key.

    The default value of this configuration is true. Users can override it to false:

    • When using SpringBoot

      Modify application.yml or application.properties and set jimmer.foreign-key-enabled-by-default to false

    • When not using SpringBoot

      JSqlClient sqlClient = JSqlClient
      .newBuilder()
      .setForeignKeyEnabledByDefault(false)
      ...Omit other configurations...
      .build();