One-To-Many relationship with additional table and extra column. How to represent it in Java class?

Viewed 81

I'm working on Calorie Counter Application. After logging in, each user will only have access to their meals.

I have a database like below:

Database schema

I'll display all information like the template below.

Meal 1
Chicken breast 100g 130kcal
Apple 200g 100kcal
Tomatoes 300g 30kcal
Meal 2
Chicken breast 100g 130kcal
Apple 200g 100kcal
Tomatoes 300g 30kcal

User class:

    @Entity
    @Table(name = "users")
    public class User {
    
        private int id;
        private String username;
        private String password;
        private int age;
        private String email;
        private Gender gender;
        private List<Meal> meals;
    
        public User() {
        }
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        @Column(name = "username")
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        @Column(name = "password")
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        @Column(name = "age")
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Column(name = "email")
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        @Column(name = "gender")
        public Gender getGender() {
            return gender;
        }
    
        public void setGender(Gender gender) {
            this.gender = gender;
        }
    
        @OneToMany(mappedBy = "user")
        public List<Meal> getMeals() {
            return meals;
        }
    
        public void setMeals(List<Meal> meals) {
            this.meals = meals;
        }
    
        private enum Gender{
            MALE,
            FEMALE
        }
    }

Meal class:

        @Entity
        @Table(name = "meals")
        public class Meal {
        
            private int id;
            private LocalDate date = LocalDate.now();
            private User user;
            private List<MealFoodProduct> mealFoodProducts;
        
            public Meal() {
            }
        
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            @Column(name = "id")
            public int getId() {
                return id;
            }
        
            public void setId(int id) {
                this.id = id;
            }
        
            @OneToMany(mappedBy = "foodProduct")
            public List<MealFoodProduct> getMealFoodProducts() {
                return mealFoodProducts;
            }
        
            public void setMealFoodProducts(List<MealFoodProduct> mealFoodProducts) {
                this.mealFoodProducts = mealFoodProducts;
            }
        
            @Column(name = "created_at")
            public LocalDate getDate() {
                return date;
            }
        
            public void setDate(LocalDate date) {
                this.date = date;
            }
        
            @ManyToOne
            @JoinColumn(name = "user_id")
            public User getUser() {
                return user;
            }
        public void setUser(User user) {
            this.user = user;
        }
    }

FoodProduct class:

    @Entity
    @Table(name = "food_products")
    public class FoodProduct {
    
        private int id;
        private String productName;
        private Double proteins;
        private Double fats;
        private Double carbohydrates;
        private Double calories;
    
        public FoodProduct() {
        }
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        @Column(name = "product_name")
        public String getProductName() {
            return productName;
        }
    
        public void setProductName(String productName) {
            this.productName = productName;
        }
    
        @Column(name = "proteins")
        public Double getProteins() {
            return proteins;
        }
    
        public void setProteins(Double proteins) {
            this.proteins = proteins;
        }
    
        @Column(name = "fats")
        public Double getFats() {
            return fats;
        }
    
        public void setFats(Double fats) {
            this.fats = fats;
        }
    
        @Column(name = "carbohydrates")
        public Double getCarbohydrates() {
            return carbohydrates;
        }
    
        public void setCarbohydrates(Double carbohydrates) {
            this.carbohydrates = carbohydrates;
        }
    
        @Override
        public String toString() {
            return productName;
        }
    
        @Column(name = "calories")
        public Double getCalories() {
            return calories;
        }
    
        public void setCalories(Double calories) {
            this.calories = calories;
        }
    }

MealFoodProcuct class

    @Entity
    @Table(name = "meals_food_products")
    public class MealFoodProduct {
        
        private Meal meal;
        private FoodProduct foodProduct;
        private double weight;
    
        public MealFoodProduct() {
        }
    
        @ManyToOne
        @JoinColumn(name = "meal_id")
        public Meal getMeal() {
            return meal;
        }
    
        public void setMeal(Meal meal) {
            this.meal = meal;
        }
    
        @ManyToOne
        @JoinColumn(name = "food_product_id")
        public FoodProduct getFoodProduct() {
            return foodProduct;
        }
    
        public void setFoodProduct(FoodProduct foodProduct) {
            this.foodProduct = foodProduct;
        }
    
        @Column(name = "food_product_weight")
        public double getWeight() {
            return weight;
        }
    
        public void setWeight(double weight) {
            this.weight = weight;
        }
    
    }

My questions:

  1. Is it correct way to connect these classes?
  2. What should be an ID in MealFoodProduct class?
1 Answers

I would suggest you to use composite identifiers with @IdClass for the MealFoodProduct entity.

@Entity
@Table(name = "meals_food_products")
@IdClass( MealFoodProductPK.class )
public class MealFoodProduct {
    
    @Id
    @ManyToOne
    @JoinColumn(name = "meal_id")
    public Meal getMeal() {
        return meal;
    }

    @Id
    @ManyToOne
    @JoinColumn(name = "food_product_id")
    public FoodProduct getFoodProduct() {
        return foodProduct;
    }

    // ...
}

public class MealFoodProductPK implements Serializable {

   private Meal meal;
   private FoodProduct foodProduct;

   public MealFoodProductPK(Meal meal, FoodProduct foodProduct) {
      this.meal = meal;
      this.foodProduct = foodProduct;
   }

   public MealFoodProductPK() {
   }

   //Getters, setters, equals, hashCode are omitted for brevity
}

Additional details see here.

P.S. Other parts of your mapping look good.

Related