I'm very new to spring boot. I am creating a health centre management system where I have 2 entities Doctor & Patient.
There are few rules that are followed
There can many doctors in a centre
There can be multiple patients too
A doctor can see multiple patients a day
But a patient can only have an appoinment with a single doctor at a time.
This is my Doctor entity:
package com.sb.projects.java.spring.medical_api.entities;
import com.sun.istack.NotNull;
import javax.persistence.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
#Entity
public class Doctors {
#Id
#NotNull
private int id;
private String name;
private String email;
private String degree;
private String specialization;
#OneToMany
private Set<Patients> patient = new HashSet<>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getDegree() {
return degree;
}
public void setDegree(String degree) {
this.degree = degree;
}
public String getSpecialization() {
return specialization;
}
public void setSpecialization(String specialization) {
this.specialization = specialization;
}
public Set<Patients> getPatient() {
return patient;
}
public void setPatient(Set<Patients> patient) {
this.patient = patient;
}
}
This is my Patient entity:
package com.sb.projects.java.spring.medical_api.entities;
import com.sun.istack.NotNull;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
#Entity
public class Patients {
#Id
#NotNull
private int id;
private String name;
private String email;
private String contact_no;
#ManyToOne
private Doctors doctor;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getContact_no() {
return contact_no;
}
public void setContact_no(String contact_no) {
this.contact_no = contact_no;
}
public Doctors getDoctor() {
return doctor;
}
public void setDoctor(Doctors doctor) {
this.doctor = doctor;
}
}
Here are the few problems that I'm facing
I'm not sure about the type of relationship that I'm setting between the Doctor and Patient Enity is correct
If the relationship is correct then I'm not sure about the setPatient setter function in Doctor entity, that my implentation of the setter function is the right way of doing the thing or not
If the all the above points are okay then what will be a perfect mockup json object which will be in a http POST request body to test the Doctor Entity
Thanks for your help in advance.
I think you can create a Doctor without taking any patient into account something like this:
POST http://locahost:8080/v1/doctors
{
"name": "doctorName",
"email": "somemail#xyz.com",
"degree": "xyz",
"specialization": "a"
}
When you want to add a patient to your doctor then you would just call another endpoint to create a visit between your doctor and your patient
POST http://localhost:8080/visits/{patientId}
body...
{
"doctorId": idOfDoctor,
}
With this you would attack the patient's db repository to create a relation between your patient and your doctor.
It sounds extrange to me to relate directly the doctor with the patients, i would do a middle relation like "VISITS" with the day of visit and the hour...
Related
I want to get the metadata of a Spring Data JPA entity as JSON for sending REST response to front end application.
I am using Spring Boot with Spring Data JPA with REST.
Role.java
package com.myapp;
import java.io.Serializable;
import javax.persistence.*;
#Entity
#Table(name = "role")
public class Role implements Serializable {
#Id
private int id;
private String name;
public Role() {}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name= name;
}
}
User.java
package com.myapp;
import java.io.Serializable;
import javax.persistence.*;
#Entity
#Table(name = "user")
public class User implements Serializable {
#Id
private int id;
private String name;
#ManyToOne
#JoinColumn(name = "user_role")
private Role role;
private Boolean status;
public User() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name= name;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public Boolean getStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
}
I want the output for User.java as follows
{
"id": "int/integer",
"name": "String",
"role": { "id": "int/integer", "name": "String" },
"status": "Boolean"
}
Is this possible?
I have started testing with spring boot to create a Restful webservice that has
simple crud functions.i have two entity classes
Company.java
#Entity
#Table(name="Company_new")
public class Company {
#Id
#NotNull
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public void setId(int id) {
this.id = id;
}
#NotNull
#Column(name="name")
private String name;
#OneToMany(mappedBy="company",cascade=CascadeType.ALL)
private Set<User> users;
public Company(String name){
this.name = name;
}
public Company(){
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public int getId(){
return id;
}
}
and User.java
#Entity
#Table(name="user_new")
public class User {
#Id
#Column
#GeneratedValue(strategy = GenerationType.AUTO)
private int idUser;
#NotNull
#Column
private String name;
#NotNull
#Column
private String userName;
#NotNull
#Column
private String authLevel;
#Column
private String password;
#ManyToOne
#JoinColumn(name="idCompany")
private Company company;
// Public methods
public Company getCompany(){
return company;
}
public void setCompany(Company company){
this.company = company;
}
public void setName(String name){
this.name =name;
}
public void setUserName(String userName){
this.userName = userName;
}
public String getName(){
return this.name;
}
public String getUsername(){
return this.userName;
}
public String getPassword(){
return this.password;
}
public String getAuthLevel() {
return authLevel;
}
public void setAuthLevel(String authLevel) {
this.authLevel = authLevel;
}
public String getUserName() {
return userName;
}
public void setId(int idUser) {
this.idUser = idUser;
}
public void setPassword(String password) {
this.password = password;
}
public int getId(){
return this.idUser;
}
}
i want to have a relationship with a Company having many users.
I have tried presisting a user record like this
#Autowired
CompanyDao companyDao;
#RequestMapping(value = "/user/create", method = RequestMethod.POST)
public #ResponseBody ResponseEntity createUser(#RequestBody User user) {
try {
Company c = companyDao.findOne(user.getCompany().getId());
user.setCompany(c);
userDao.save(user);
} catch (Exception e) {
return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(user, HttpStatus.OK);
}
my data is presisting in the database the way i want
but when i try to access a company record it loads like this
obviously it loads relationships in a cycle and eventually gives stack overflow error. how to solve this ?
Depending on your desired outcome you can:
use #JsonIgnore on public Set<User> getUsers() to prevent serializing the users collection or #JsonIgnore on public Company getCompany() to prevent company serialization
use #JsonManagedReference on public Set<User> getUsers() and #JsonBackReference on public Company getCompany() to let Jackson know that it's a bidirectional relation.
PS. If the API you're exposing will be consumed by code you do not control consider not exposing entities directly but mapping them to DTOs
I am trying to perform join in hibernate and i am using struts2.
I am working with hibernate using annotaions. Now i am unable to perform join between two tables.My first table is "studentprojects" which contain pid and email.Second table is "initialprojectdetials" which contains pid,name,description... similarly some other fields.I have to get the data of second table by performing join around pid of first table.
For this am using this query:
String hql="from InitialProjectDTO I join I.projectId S where I.projectId=:id";
Query query=session.createQuery(hql);
query.setParameter("id", id);
mail =query.list();
where mail is the arraylist of InitialProjectDTO.
And my InitialProjectDTO is:
package edu.pma.dto;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name="initialprojectdetail")
public class InitialProjectDTO {
#Id
#Column(name="projectId")
#OneToMany(cascade=CascadeType.ALL)
#JoinTable(name="studentprojects",joinColumns=#JoinColumn(name="projectId"))
int projectId;
#Column(name="name")
String name;
#Column(name="description")
String description;
#Column(name="technology")
String technology;
#Column(name="guide")
String guide;
#Column(name="duration")
int duration;
#Column(name="status")
String status;
#Column(name="report")
String report;
public String getReport() {
return report;
}
public void setReport(String report) {
this.report = report;
}
public int getProjectId() {
return projectId;
}
public void setProjectId(int projectId) {
this.projectId = projectId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getTechnology() {
return technology;
}
public void setTechnology(String technology) {
this.technology = technology;
}
public String getGuide() {
return guide;
}
public void setGuide(String guide) {
this.guide = guide;
}
public int getDuration() {
return duration;
}
public void setDuration(int duration) {
this.duration = duration;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
my SudentProjectDTO is:
package edu.pma.dto;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="studentprojects")
public class StudentProjectDTO {
public int getProjectId() {
return projectId;
}
public void setProjectId(int projectId) {
this.projectId = projectId;
}
#Id
#Column(name="email")
String email;
#Column(name="projectId")
int projectId;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
This is the error which i am getting:
Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements: edu.pma.dto.InitialProjectDTO.projectId
Method "execute" failed for object edu.pma.actions.LoginAction#1096a56
File: org/hibernate/cfg/annotations/CollectionBinder.java
You should try to use different models
#Entity
public class InitialProjectDTO {
#OneToMany(mappedBy = "project")
private Collection<StudentProjectDTO> students;
}
#Entity
public class StudentProjectDTO {
#ManyToOne
private InitialProjectDTO project;
}
And with the proper model it shuld be easy to write hql, you might want to look here for examples https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html.
Also I would suggest to look here for example of models. http://viralpatel.net/blogs/hibernate-one-to-many-annotation-tutorial/
See following example might its help to you
#Entity
#Table(name="initialprojectdetail")
public class InitialProjectDTO {
private Integer initialProjectDTOId;
private Set<StudentProjectDTO > studentProjectDTO = new HashSet<StudentProjectDTO >(0);
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "initial_projectDTO_id", unique = true, nullable = false)
public Integer getInitialProjectDTOId() {
return this.initialProjectDTOId;
}
public void setInitialProjectDTOId(Integer initialProjectDTOId) {
this.initialProjectDTOId = initialProjectDTOId;
}
#OneToMany(mappedBy = "studentprojects", cascade = CascadeType.ALL, fetch=FetchType.LAZY)
public Set<StudentProjectDTO> getUserRole() {
return this.studentProjectDTO;
}
public void setUserRole(Set<StudentProjectDTO> studentProjectDTO) {
this.studentProjectDTO = studentProjectDTO;
}
}
#Entity
#Table(name="studentprojects")
public class StudentProjectDTO {
private InitialProjectDTO project;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "initial_projectDTO_id", nullable = false)
public User getProject() {
return this.project;
}
public void setProject(InitialProjectDTO project) {
this.project = project;
}
}
your Query shoud be something like this
String hql="SELECT ip from InitialProjectDTO ip JOIN ip.studentProjectDTO sp WHERE sp.projectId = :id";
Query query=session.createQuery(hql);
query.setParameter("id", id);
mail =query.list();
I have created Three classes- User, UserSubscription and Subscription. I want that users in the UserSubscription table should be referenced by the users existing in the User table. So, how to use mappedBy?
The classes are as follows:
User:
package com.model;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToOne;
#Entity
public class User {
private int userId;
private String password;
private String contact;
private String firstName;
private String lastName;
private String gender;
private String address;
private int age;
private String email;
private String countBooks;
private Set<Language> languages = new HashSet<Language>(0);
private Set<Book> favorites = new HashSet<Book>(0);
#Id
#GeneratedValue
#Column(name="User_Id")
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
#Column(name="Password")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Column(name="Contact")
public String getContact() {
return contact;
}
public void setContact(String contact) {
this.contact = contact;
}
#Column(name="First_Name")
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Column(name="Last_Name")
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Column(name="Gender")
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
#Column(name="Address")
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
#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="Count_Books")
public String getCountBooks() {
return countBooks;
}
public void setCountBooks(String countBooks) {
this.countBooks = countBooks;
}
#ManyToMany(cascade=CascadeType.ALL)
#JoinTable(name="User_Language", joinColumns = {
#JoinColumn(name = "User_Id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "Language_Id",
nullable = false, updatable = false) })
public Set<Language> getLanguages() {
return languages;
}
public void setLanguages(Set<Language> languages) {
this.languages = languages;
}
#ManyToMany
#JoinTable(name="User_Favorite", joinColumns = {
#JoinColumn(name = "User_Id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "Book_Id",
nullable = false, updatable = false) })
public Set<Book> getFavorites() {
return favorites;
}
public void setFavorites(Set<Book> favorites) {
this.favorites = favorites;
}
}
UserSubscription:
package com.model;
import java.sql.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
#Entity
public class UserSubscription {
private int userSubscriptionId;
private Subscription subscription;
private User user;
private Date subscriptionStartDate;
private Date subscriptionEndDate;
private int status;
#Id
#GeneratedValue
#Column(name="User_Subscription_Id")
public int getUserSubscriptionId() {
return userSubscriptionId;
}
public void setUserSubscriptionId(int userSubscriptionId) {
this.userSubscriptionId = userSubscriptionId;
}
#Column(name="Subscription_Id")
public Subscription getSubscription() {
return subscription;
}
public void setSubscription(Subscription subscription) {
this.subscription = subscription;
}
#OneToOne(mappedBy="userId")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
#Column(name="Subscription_Start_Date")
public Date getSubscriptionStartDate() {
return subscriptionStartDate;
}
public void setSubscriptionStartDate(Date subscriptionStartDate) {
this.subscriptionStartDate = subscriptionStartDate;
}
#Column(name="Subscription_End_Date")
public Date getSubscriptionEndDate() {
return subscriptionEndDate;
}
public void setSubscriptionEndDate(Date subscriptionEndDate) {
this.subscriptionEndDate = subscriptionEndDate;
}
#Column(name="Status")
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
}
Subscription:
package com.model;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
#Entity
public class Subscription {
private int subscriptionId;
private String name;
private int period;
private float fees;
private int noOfBooks;
private int Status;
#Id
#GeneratedValue
public int getSubscriptionId() {
return subscriptionId;
}
public void setSubscriptionId(int subscriptionId) {
this.subscriptionId = subscriptionId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPeriod() {
return period;
}
public void setPeriod(int period) {
this.period = period;
}
public float getFees() {
return fees;
}
public void setFees(float fees) {
this.fees = fees;
}
public int getNoOfBooks() {
return noOfBooks;
}
public void setNoOfBooks(int noOfBooks) {
this.noOfBooks = noOfBooks;
}
public int getStatus() {
return Status;
}
public void setStatus(int status) {
Status = status;
}
}
Exception while executing:
Exception in thread "main" org.hibernate.AnnotationException: Referenced property not a (One|Many)ToOne: com.model.User.userId in mappedBy of com.model.UserSubscription.user
at org.hibernate.cfg.OneToOneSecondPass.doSecondPass(OneToOneSecondPass.java:248)
at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1695)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1424)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1928)
at com.impetus.model.Check.main(Check.java:92)
In your code, user-user_subscription looks uni-directional. 'mappedby' should be used in bi-directional relationship.
You can use following code in user entity to make it bi-directional with user_subscription.
private UserSubscription userSubscription;
#OneToOne
public User getUserSubscription() {
return userSubscription;
}
Or remove mappedby from user_subscription and make it unidirectional.
Seems you are unsure of what mappedBy is used for or means. Database relationships are one sided; one table will have a foreign key reference to the target table. In JPA, you might map this relationship as a OneToOne and specify the foreign key to use with the #JoinColumn annotation:
#OneToOne(mappedBy="userId")
#JoinColumn(name = "USER_ID")
public User getUser() {
return user;
}
The Join column definition is optional, and if not used JPA will default to using the attribute name with "_" and the target entity's ID name prepended, so "USER_ID" in this case anyway.
Back to the database, because target table is referenced by the source table, this forms another implicit relationship back (the target table's ID can be used to look up the other table's foreign key). In JPA, this can be mapped again as a OneToOne or a OneToMany depending on the cardinality. If it is a OneToOne, you specify that this relationship does not define the foreign key by marking it as mappedBy the other relationship:
#OneToOne(mappedBy="user")
public UserSubscription getUserSubscription() {
return userSubscription;
}
But it is more likely a User will have multiple userSubscriptions:
#OneToMany(mappedBy="user")
public Collection<UserSubscription> getUserSubscriptions () {
return userSubscription ;
}
In both cases, you use the mappedBy to signal that there is a 'user' attribute in the target entity that defines a relationship to this entity and controls the foreign key setting in the database.
You also need to change how your define the UserSubscription->Subscription relationship, as you have defined an #Column on what appears to be a relationship. It should probably be
#OneToOne
#JoinColumn(name="Subscription_Id")
public Subscription getSubscription() {
return subscription;
}
you should have UserSubscription memeber and corrosponding gettes and setters in your User class like below:
private Set<Company> userSubscriptions = new HashSet<Company>(0);
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
public Set<UserSubscription> getUserSubscriptions() {
return this.userSubscriptions ;
}
public void setUserSubscriptions(Set<UserSubscription> userSubscriptions ) {
this.userSubscriptions = userSubscriptions ;
}
and same way you should have user object as memeber in UserSubscription Entity class.
private User user;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USER_ID", nullable = false)
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
You are doing it wrong
class User {
UserSubscription userSubscription ;
#OneToOne
public UserSubscription getUserSubscription(){
return userSubscription ;
}
public void setUserSubscription(UserSubscription userSubscription ){
this.userSubscription = userSubscription ;
}
}
class UserSubscription {
#OneToOne(mappedBy="userSubscription")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
If I create a Customer and Controller, then associate my Controller with a customer it saves fine.
If I then remove my controller it doesn't remove the relationship between them.
This causes an EntityNotFoundException when I load the Customer.
javax.persistence.EntityNotFoundException: Unable to find Controller with id 22
I'd like to know how to map this so that when a Controller is deleted the relationship is also deleted.
Database Tables
customer
controller
customer_controllers - mapping table.
The Controller's id is not getting removed from the customer_controllers mapping table.
#Entity
public class Customer implements Serializable{
private Integer id;
private Set<Controller> controllers;
#Id
#GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToMany(cascade={CascadeType.ALL})
public Set<Controller> getControllers()
{
return controllers;
}
public void setControllers(Set<Controller> controllers)
{
this.controllers = controllers;
}
}
#Entity
public class Controller implements Serializable{
private Integer id;
private String name;
private String abbreviation;
#Id
#GeneratedValue
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAbbreviation()
{
return abbreviation;
}
public void setAbbreviation(String abbreviation)
{
this.abbreviation = abbreviation;
}
}
If you have a ManyToMany then you should map Controller to Customer with a
#ManyToMany(mappedBy="controllers")
or the other way around, depending on which side is the owning side.
As you have it now the relation is not fully defined and it will fail on events like "Cascade".
Have you checked the javadoc for #ManyToMany?
It includes the above example mappings.
you need to make the relationship bidirectional, so that the controller object is aware of its relationship to the customer. Yhis means that when the controller is deleted the record in the join table is also deleted.
This isn't the exact mapping but it gives you the idea.
#Entity
public class Controller implements Serializable{
private Integer id;
private String name;
private String abbreviation;
private Set<Customer> customers;
#Id
#GeneratedValue
public Integer getId()
{
return id;
}
public void setId(Integer id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getAbbreviation()
{
return abbreviation;
}
public void setAbbreviation(String abbreviation)
{
this.abbreviation = abbreviation;
}
#ManyToMany(cascade={CascadeType.ALL})
public Set<Customer> getCustomers()
{
return customers;
}
public void setCustomers(Set<Customers> customers)
{
this.customers= customers;
}
}