Search code examples
jpamany-to-many

Correct way to do a join table with an additional attribute in JPA?


I've got the following entities (simplified for the purpose of this thread):

Product.java

@Entity
@Table(name = "Product")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(nullable = false)
    private String name;
    
    // getters, setters,...
}

Ingredient.java

@Entity
@Table(name = "Ingredient")
public class Ingredient {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(nullable = false)
    private String name;

    // getters, setters,...
}

And I'd like to add a many to one relationship to represent a product being made of certain amount of some ingredients.

Something like the following would only hold the information about which ingredients a product is made of, but it wouldn't tell me about the amount each ingredient it contains. What's the most JPA way to add a simple amount attribute to the join table?

Product.java

@Entity
@Table(name = "Product")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(nullable = false)
    private String name;

    @ManyToMany
    @JoinTable(
        name = "Product_Ingredient",
        joinColumns = @JoinColumn(name = "product_id"),
        inverseJoinColumns = @JoinColumn(name = "ingredient_id")
    )
    private List<Ingredient> ingredients;

    // getters, setters,...
}

Solution

  • It can be done with an additional entity containing the amount and two many-to-one relationships. One to Product other to Ingredient. The table will consist of two ids and the amount.

    Solution

    Additional entity:

    @Entity
    class ProductIngredient {
    
        @Id
        Long id;
    
        @ManyToOne
        @JoinColumn(name = "product_id")
        Product product;
    
        @ManyToOne
        @JoinColumn(name = "ingredient_id")
        Ingredient ingredient;
    
        BigDecimal amount;
        
        // ...
    }
    

    The relationships in existing entities:

    class Product {
    
        // ...
    
        @OneToMany(mappedBy = "product")
        Set<ProductIngredient> productIngredients;
    
        // ...
    }
    class Ingredient {
    
        // ...
    
        @OneToMany(mappedBy = "ingredient")
        Set<ProductIngredient> productIngredients;
    
        // ...
    }