Alpit Anand
Alpit Anand

Reputation: 1258

What is foreignKey and inverseForeignKey in @JoinTable annotation?

I am having a project where I found, a schema something like this

@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data

@EqualsAndHashCode
@ToString(callSuper = true)
@IdClass(QuarantinePolicyIdentity.class)
@Entity(name = PolicyServiceConstants.QUARANTINE_POLICY_TABLE)
@Table(uniqueConstraints = @UniqueConstraint(name = PolicyServiceConstants.QUARANTINE_POLICY_UNIQUE_NAME_CONSTRAINT,
        columnNames = {"customerUuid", "name"}),
        indexes = {@Index(name = PolicyServiceConstants.QUARANTINE_POLICY_UNIQUE_INDEX,
                columnList = "orderNo",
                unique = false)
        })
public class QuarantinePolicyEntity {

    @Id
    private String quarantinePolicyId;

    @Id
    @JsonIgnore
    private String customerUuid;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @JoinTable(name = PolicyServiceConstants.QUARANTINE_POLICY_OUTBOUND_RULE_TABLE,
            foreignKey = @ForeignKey(name = PolicyServiceConstants.FOREIGN_KEY_QUARANTINE_POLICY_QPOR),
            inverseForeignKey = @ForeignKey(name = PolicyServiceConstants.FOREIGN_KEY_QUARANTINE_POLICY_ORQP))
    private Set<RuleEntity> outboundRules;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @JoinTable(name = PolicyServiceConstants.QUARANTINE_POLICY_INBOUND_RULE_TABLE,
            foreignKey = @ForeignKey(name = PolicyServiceConstants.FOREIGN_KEY_QUARANTINE_POLICY_QPIR),
            inverseForeignKey = @ForeignKey(name = PolicyServiceConstants.FOREIGN_KEY_QUARANTINE_POLICY_IRQP))
    private Set<RuleEntity> inboundRules;

    private String createdBy;

    private Date createdDate;

    private String lastModifiedBy;

    private Date lastModifiedDate;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof QuarantinePolicyEntity)) return false;
        QuarantinePolicyEntity that = (QuarantinePolicyEntity) o;
        return com.google.common.base.Objects.equal(getQuarantinePolicyId(), that.getQuarantinePolicyId()) &&
                com.google.common.base.Objects.equal(getCustomerUuid(), that.getCustomerUuid());
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), quarantinePolicyId, customerUuid);
    }

}

Thanks.

Upvotes: 0

Views: 623

Answers (1)

Shafin Mahmud
Shafin Mahmud

Reputation: 4081

What does the JPA documentation say?

If you visit the JoinTable annotation doc you will find

foreignKey (Optional) Used to specify or control the generation of a foreign key constraint for the columns corresponding to the joinColumns element when table generation is in effect.

inverseForeignKey (Optional) Used to specify or control the generation of a foreign key constraint for the columns corresponding to the inverseJoinColumns element when table generation is in effect.

Do you really need these?

So you can see these two attributes are defining the foreign key contraint creation during schema generation. Not the foreign key itself. The foreign keys are defined with the joinColumns and inverseJoinColumns attribute.

Now if you dont put those foreignKey and inverseForeignKey, then the default value is ConstraintMode.PROVIDER_DEFAULT that means the database you are using (Oracle here) will decide the name of the foreign key constraint.

So you dont really need to explicitly provide the foreignKey and inverseForeignKey unless you want. These are optional attribute.

More ways to improve the association

  • I dont know wheather its a working code or not. But actually the OneToMany association is not properly defined here. There is no joinColumns and inverseJoinColumns association (so nothing is telling which column to map). The association should be defined this way

      @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
      @JoinTable(name = "join_table_name",
                 joinColumns = @JoinColumn(name = "column_a"),
                 inverseJoinColumns = @JoinColumn(name = "column_b"),
                 foreignKey = @ForeignKey(name = "name_of_the_constraint_for_column_a"),
                 inverseForeignKey = @ForeignKey(name = "name_of_the_constraint_for_column_b"))
      private Set<RuleEntity> outboundRules;
    
  • Moreover you dont even need a JoinTable for a OneToMany association either. Simply a JoinColumn should do the job. Think about the association, if its unidirectional or bi directional or which side is the owning side of the relationship. You will find handful of options to optimize your association.

More read:

Upvotes: 2

Related Questions