JPA mappedBy reference an unknown target entity property - java

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.

Related

Extra association table is created in spring boot

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<>();

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.

Java Repository Query findAll() given an ID from another class (Foreign-Key)

I'm using a JPARepository called PublicationRepository and want to find all Publications from a certain Person. This Classes are connected over the Class Author.
Person Class:
#Entity
public class Person {
#Id
private String email;
private String telefon;
private String password;
#OneToMany(mappedBy = "person")
Set<Author> Author;
}
Author Class:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Author {
#Id
private int id;
#ManyToOne
#JoinColumn(name="Person_ID")
Person person;
#ManyToOne
#JoinColumn(name="Publication_ID")
Publication publication;
private String Date;
private String Writerstatus;
}
Publication Class
#Entity
#AllArgsConstructor
#NoArgsConstructor
#Data
public class Publication {
#Id
private int id;
private String publicationname;
#OneToMany(mappedBy = "publication")
Set<Author> author;
}
And the PublicationRepository
public interface ProjektRepository extends JpaRepository<Projekt,Integer> {
}
public interface PublicationRepository extends JpaRepository<Publication,Integer> {
#Query(value = "SELECT pub.* FROM author as auth INNER JOIN publications as pub ON auth.publication_id = pub.id WHERE auth.person_id = ?1", native = true)
List<Publication> findAllPublicationsOfThisPerson(int personId);
}
Try this.
I would also recommend to annotate the entities with their table names:
#Table(name = "publication")
You use a manually build table for a Many-to-Many relationship Author
You could also delegate that to Spring Data Jpa by using #ManyToMany Annotation.
A good tutorial:
https://attacomsian.com/blog/spring-data-jpa-many-to-many-mapping

How to create a simple connection table in Java?

I am trying to set up a very simple database with two tables in Java and connect them using a specific connection table.
1st table Student consists of id, first_name and last_name.
2nd table Course consists of id and name.
The connection table called Enrollment should have course_id and student_id that originate from 1st and 2nd tables.
My problem is I don't know how to map the IDs when extending Spring Data JPA's AbstractPersistable, which has an auto-increment primary key field in it.
My code:
Student:
// Package
// Imports
#Entity
#Data #NoArgsConstructor #AllArgsConstructor
public class Student extends AbstractPersistable<Long> {
private String first_name;
private String last_name;
}
Course:
// Package
// Imports
#Entity
#Data #NoArgsConstructor #AllArgsConstructor
public class Course extends AbstractPersistable<Long> {
private String name;
}
I have tried different usages of #ManyToMany annotation but since the primary key ID is handled by AbstractPersistable, I have failed to map the 'invisible' IDs for the connection table.
I also know that the connection table and its columns can be named with #Column, #JoinColumn and #JoinTable. I haven't gotten that far yet.
Hi i would try something like this ...
#Entity
#Data #NoArgsConstructor #AllArgsConstructor
public class Student extends AbstractPersistable<Long> {
private String first_name;
private String last_name;
#ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "enrollment",
joinColumns = #JoinColumn(name = "student_id"),
inverseJoinColumns = #JoinColumn(name = "course_id")
)
private List<Course> courses;
}
#Entity
#Data #NoArgsConstructor #AllArgsConstructor
public class Course extends AbstractPersistable<Long> {
private String name;
#ManyToMany(mappedBy = "courses")
private List<Student> students;
}

Spring-Data-Neo4j: relationshipEntity return only graphId for nodes.

I am creating an example using Spring-Data-Neo4j . In this, perform CRUD operations, and all operation run successfully. But when i fetch the relationa ship collection from entity, it return only graphId for nodes, and other values are null. Following is my code. If i do something wrong, please correct me.
Entities:
#NodeEntity
#ToString(callSuper=true, exclude={"movies"})
#EqualsAndHashCode(callSuper = true, exclude = {"name", "movies"})
public class Person extends BaseEntity{
#Getter #Setter
#Indexed(unique = true)
private Long id;
#Getter #Setter
private String name;
#Getter #Setter
#RelatedToVia(type = RelationshipTypes.FRIEND, elementClass = FriendsRelationship.class, direction = Direction.BOTH)
private Set<FriendsRelationship> friends;
}
#RelationshipEntity(type=RelationshipTypes.FRIEND)
public class FriendsRelationship extends BaseEntity{
#StartNode
#Getter #Setter
private Person person;
#EndNode
#Getter #Setter
private Person friend;
#Getter #Setter
private String friendsType;
}
Create Relationship:
public FriendsRelationship createRelationshipBetweenPersons(Person person, Person friend,
Class<FriendsRelationship> relationshipEntity, String friendshipType) {
FriendsRelationship relationship = neo4jTemplate.createRelationshipBetween(person, friend, relationshipEntity, friendshipType, true);
neo4jTemplate.save(relationship);
return relationship;
}
Controller:
#RequestMapping(value="find-person-by-id", method=RequestMethod.POST)
public String findPersonById(long id, Model model) {
Person person = personService.findPersonByProperty("id", id);
model.addAttribute("actor", person);
model.addAttribute("personFriends", person.getFriends());
return "person/view-person-detail";
}
In controller, when i fetch the person, the person fetch successfully, but i fetch the friends, it contain start_node with same person object, but end_node contain person object with graphId value only, others values are null.
For solve this problem, we need to add #Fetch annotation at start-node and end-node in FriendsRelationship entity, like as below:
#RelationshipEntity(type=RelationshipTypes.FRIEND)
public class FriendsRelationship extends BaseEntity{
#Fetch #StartNode
#Getter #Setter
private Person person;
#Fetch #EndNode
#Getter #Setter
private Person friend;
#Getter #Setter
private String friendsType;
}
Now the data fetch successfully.

Categories