Extra association table is created in spring boot - java

I'm currently working on developing a recipe application and I'm having trouble with DB table generation.
Here are the Entity files I'm using:
// Recipe.java
#Data
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "recipes")
public class Recipe {
#Id
#GeneratedValue
private int id;
private String name;
private String description;
private String instruction;
#ManyToOne
private User user;
#OneToMany(cascade=CascadeType.ALL)
private List<RecipeIngredient> ingredients = new ArrayList<>();
}
// Ingredient.java
#Data
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "ingredients")
public class Ingredient {
#Id
#GeneratedValue
private int id;
private String name;
}
// RecipeIngredient.java
#Data
#Entity
#AllArgsConstructor
#NoArgsConstructor
public class RecipeIngredient {
#Id
#GeneratedValue
private int id;
#ManyToOne
private Ingredient ingredient;
private String amount;
}
Spring Boot Automatically creates tables for me but I just wanna have one table for RecipeIngredient, but it creates two tables for them.
It works perfectly fine but the thing I want is just how to make these two tables into one or make spring boot not generate one of them.

If you want recipe_ingedients table only delete recipeIngredient Entity Class and if you want to keep recipe_ingredient table remove this:
#OneToMany(cascade=CascadeType.ALL)
private List<RecipeIngredient> ingredients = new ArrayList<>();

Related

How to set schema location for #ManyToMany Entity Collection with JPA

I want to create 2 tables in my PostgreSQL database while using the Spring-boot JPA.
#Entity
#Table(schema = "test")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
And my User class
#Entity
#Table(schema = "test")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class User {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String group_id;
private String email;
#ManyToMany(fetch = FetchType.EAGER)
private Collection<Role> roles = new ArrayList<>();
}
The 2 tables above are created in test schema but the user_roles is trying to be created without any schema selected and I get the error
Caused by: org.postgresql.util.PSQLException: ERROR: no schema has been selected to create in
So my question is: How to assign the schema to the user_roles table that JPA is trying to create

JPA mappedBy reference an unknown target entity property

Hello I am new to JPA Spring boot and right now I am trying to make a connection between two tables into a third one. So I have a Doctor and Patient table with it's properties, where one Doctor can examine every patient and a patient can visit every doctor.But in one examination there can be no more than one patient and one doctor. For the doctors I want to keep the information of which patients they have examined, respectively for the patients, which doctors they were examined from. I would like to create a middle table called DoctorVisit where I have the id of the doctor who did the examination and the id of the patient with some more properties like date,medicines and etc. When I try to do this I am getting an error - "mappedBy reference an unknown target entity property: /.../Patient.examinedByDoctors". If I remove the #OneToMany connection in Patient the code compiles. I would be really happy if someone can explain me where is the mistake. Thank you in advance
BaseEntity class:
#Getter
#Setter
#NoArgsConstructor
#MappedSuperclass
public class BaseEntity {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private long id;
}
Doctor class:
#Getter
#Setter
#NoArgsConstructor
#Entity
#Table(name="doctor")
public class Doctor extends BaseEntity{
private String name;
#ManyToMany(mappedBy ="doctors")
private Set<Specialty> specialties;
#OneToMany(mappedBy ="doctor")
private Set<Patient> GpOfPatients;
#OneToMany(mappedBy = "doctor")
private List<Patient> examinedPatients;
}
Patient class:
#Getter
#Setter
#NoArgsConstructor
#Entity
#Table(name="patient")
public class Patient extends BaseEntity{
private String name;
private String EGN;
private boolean insurancesPaidInLastSixMonths;
#ManyToOne
#JoinColumn(name="gp_id")
private Doctor doctor;
#OneToMany(mappedBy = "patient")
private List<Doctor> examinedByDoctors;
}
Specialty class:
#Getter
#Setter
#NoArgsConstructor
#Entity
#Table(name="specialty")
public class Specialty extends BaseEntity{
private String specialtyName;
#ManyToMany
#JoinTable(name="doctors_specialties",joinColumns = #JoinColumn(name="specialty_id"),
inverseJoinColumns = #JoinColumn(name="doctor_id"))
private Set<Doctor> doctors;
}
DoctorVisit class:
#Getter
#Setter
#NoArgsConstructor
#Entity
#Table(name="doctorvisit")
public class DoctorVisit extends BaseEntity {
#ManyToOne
#JoinColumn(name = "patient_id")
private Patient patient;
#ManyToOne
#JoinColumn(name="doctor_id")
private Doctor doctor;
private Date date;
private String diagonosis;
#ManyToMany(mappedBy = "prescribedToPatients")
private Set<Medicine> medicines;
private int patientChart;
}
Medicine class:
#Getter
#Setter
#Entity
#Table(name = "medicine")
public class Medicine extends BaseEntity{
private String name;
private String manufacturer;
#ManyToMany
#JoinTable(name="prescribedMedicines_to_patients",joinColumns = #JoinColumn(name="medicine_id"),
inverseJoinColumns = #JoinColumn(name="patient_id"))
private List<Patient> prescribedToPatients;
}
You get this error because the Doctor class does not have a patient field. However adding a Patient won't fit your use case, because a Doctor can have multiple Patients not just one. So you have to create a ManyToMany association between Patient and Doctor or use only the DoctorVisit to connect the two entities. I would apply the second option and use special queries to get who visited who with the DISTINCT keyword for example.

Problems making a many-to-many relationship work across 2 microservices using Spring Boot & Hibernate

So for this assignment, I'm supposed to have 2 microservices (task-service & user-service) with each having their own database.
A task can have multiple users assigned it but multiple users can be assigned to multiple tasks so therefore it's a many-to-many relationship.
Both microservices are Spring Boot applications using Hibernate and I'm struggling to make this relationship happen between task and user inside the task-service because I don't think it's a good idea to copy the user model that already exists in the user-service, over to the task-service.
This assignment assumes that there is consistency in the user-ids across both databases without using foreign keys.
For context:
Desired entity relationship diagram generated from Hibernate:
Task.java [task-service]
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#EqualsAndHashCode(callSuper = true)
public class Task extends BaseEntity {
private String name, description;
#ManyToOne
private Lane lane;
#OneToMany
private List<TaskUser> users;
}
TaskUser.java [task-service]
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Data
#EqualsAndHashCode
public class TaskUser {
#Id
private Long id;
#Column(name = "task_id")
private Long taskId;
#Column(name = "user_id")
private Long userId;
}
User.java [user-service]
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Data
#EqualsAndHashCode(callSuper = true)
#ToString(callSuper = true)
public class User extends BaseEntity {
#Column(unique = true)
private String username;
}
Currently, Hibernate is generating both a task_user & task_users table inside the task-service database and I'd like to just have 1 intermediate table instead of two.
Question: How would I make this many-to-many relationship work with Hibernate whilst working with two different microservices?
Maybe a better hibernate mapping :
Task.java [task-service]
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#EqualsAndHashCode(callSuper = true)
public class Task extends BaseEntity {
private String name, description;
#ManyToOne
private Lane lane;
#OneToMany(mappedBy="task")
private List<TaskUser> users;
}
TaskUser.java [task-service]
#Entity
#NoArgsConstructor
#AllArgsConstructor
#Data
#EqualsAndHashCode
public class TaskUser {
#Id
private Long id;
#ManyToOne
#JoinColumn(name="task_id", nullable=false)
private Task task;
#Column(name = "user_id")
private Long userId;
}
Use case: assign an already existing task to an already existing user.
You can assign multiple users at a time to 1 single task.
PostRequest
/tasks/allocation/new
Request Body:
{
"task-id": 12345,
"users": [
{
"username": "user-1",
"user-id": 101
},
{
"username": "user-2",
"user-id": 102
},
{
"username": "user-3",
"user-id": 103
}
]
}
Post request is having one task and list of user-details to be allocated to that task.
TaskAllocation.java
#Data
public class TaskAllocation{
#jsonProperty("task-id")
private long taskId;
#JsonProperty("users")
private List<Users> userList;
}
Users.java
#Data
public class Users{
#jsonProperty("username")
private String username;
#JsonProperty("user-id")
private Long userId;
}
RestController
#PostMapping("/tasks/allocation/new")
public CompletableFuture<ResponseEntity<?>> assignTaskToUsers(#ResponseBody #Valid TaskAllocation taskAllocation){
// service call
}
Inside service:
fetch the task from task db(verify if task exist)
If needed, fetch details of users from user-service(for each user), need a async or rest call to user-service. Task service is not having details of users.
For each user:
1.Create new Allocation
Set task Id
Set user-id or username
Save
Task is already existing
Table Task-Allocation
--------------------------------------------------------------
alloc-id(Pk) task-Id(Fk) user-id timetamp
--------------------------------------------------------------
1 12345 101 123123123123
2 12345 102 123123123123
3 12345 103 123123123123
Entities
Task and TaskAllocation has 1:n relationship i.e. task-allocation table consists of multiple records with same task-id.
Task.java
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "sirf_tournament")
public class Task extends Auditable<String> implements Serializable {
#Id
#GeneratedValue
private Long taskId;
private String taskName;
// others
#OneToMany(
fetch = FetchType.LAZY,
mappedBy = "task",
cascade = CascadeType.ALL,
orphanRemoval = true)
private Collection<TaskAllocation> taskAllocation = new HashSet<>();
}
TaskAllocation.java
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "sirf_tournament")
public class TaskAllocation extends Auditable<String> implements Serializable {
#Id
#GeneratedValue
private Long allocId;
private Long userId;
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "taskId")
private Task task;
// others
}
User table and other related entities are not mentioned here. Task service has no information of users.
It would be good if you verify every users(all ids can be verified in a single call, return invalid ids from user service) and task ids before persisting them into table.

Can I map multiple database tables to a unique Entity using JPA?

I am trying to add multi-language to the description and title fields of one of my Entities but without success. My Entity is like below and my database is MySQL:
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "project")
public class ProjectEntity implements Serializable {
#Id
#Column(name="id")
private Integer id;
#Column(name="team_size")
private Integer teamSize;
#Column(name="description")
private String description;
#Column(name="title")
private String title;
#OneToMany
private List<DetailsEntity> details;
}
I alreaady tried to add a projectDetails entity that contains the description and title, but as I need multilanguage, the Project will now have a list of ProjectDetails in my backend, what I don't need.
Here is what the projectDetails could looks like:
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "project_details")
public class ProjectDetails implements Serializable {
#Id
#Column(name="id")
private Integer id;
#Column(name="title")
private String title;
#Column(name="description")
private String description;
#Column(name="language")
private String language;
#Column(name="project_id")
private Integer projectId;
}
I would like to be able to do something with the JPA repository requests, like this:
#Repository
public interface ProjectEntityRepository extends JpaRepository<ProjectEntity, Integer> {
#Query("select p from ProjectEntity p left outer join ProjectDetails d on p.id=d.project_id and d.language=:language")
List<ProjectEntity> findAllForLanguage(String language);
}
Any idea on how to change part of this to return the Project entity with values of only 1 ProjectDetails?
Thank you

Multiply ID mapping throw BaseEntity

I'm mapping classes via Hibernate and I need to map multiple ID for Relationship.
All ID's extend from BaseEntity. How can I implement multiple ID mapping for Relationship which contains Foreign Key for User in DataBase ?
Basicly fields userIdOne and userIdTwo in Relationship has to contain user's id which send request.
User extend own ID from BaseEntity.
Each time I run it - get en error:
This class [class com.mylov.springsocialnetwork.model.Relationship]
does not define an IdClass
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#MappedSuperclass
#EqualsAndHashCode
public class BaseEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
#Builder
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode(exclude = {"posts"}, callSuper = false)
#Entity
public class User extends BaseEntity {
private String userName;
private String realName;
private String email;
private String phoneNumber;
private LocalDate birthDate;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "userPosted")
private Set<Post> posts = new HashSet<>();
private String password;
public User(Long id, String userName, String realName, String email, String phoneNumber, LocalDate birthDate,
Set<Post> posts, String password) {
super(id);
this.userName = userName;
this.realName = realName;
this.email = email;
this.phoneNumber = phoneNumber;
this.birthDate = birthDate;
this.posts = posts;
this.password = password;
}
}
#Builder
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class Relationship implements Serializable {
//#Id not working
private Long userIdFrom;
//#Id
private Long userIdTo;
#Enumerated(value = EnumType.STRING)
private RelationshipStatus status;
private LocalDate friendsRequestDate;
}
It appears that you are looking to establish a Relationship between two different users. This would mean that each Relationship is an object/entity of its own and should have its very own #Id (unrelated to user IDs).
The linkage to each User that form part of this Relationship should be mapped as foreign keys instead (probably #ManyToOne and a #JoinColumn).
For example:
#Entity
public class Relationship implements Serializable {
#Id
private Long relationshipId;
#ManyToOne(...)
#ForeignKey(name="FK_USER_ONE") //for generation only, it isn't strictly required
#JoinColumn(name="from")
private Long userIdFrom;
#ManyToOne(...)
#ForeignKey(name="FK_USER_TWO") //for generation only, it isn't strictly required
#JoinColumn(name="to")
private Long userIdTo;
#Enumerated(value = EnumType.STRING)
private RelationshipStatus status;
private LocalDate friendsRequestDate;
}
Edit:
It isn't required to specify the #ForeignKey annotations. They will be used if the database tables are generated automatically (ok for testing, but usually not something you'll want in production) and will create the FOREIGN KEY constraint on the table accordingly, but JPA mapping will work fine without it, because it takes the relationships from your defined model, not from the database itself.

Categories