I have 2 entities, connected by many to many. The template should list:
Owner1
shelter1
shelter 2
Owner1
shelter 1
How can I connect the Owner and the Shelter in the controller so that I can pinch into the template
Owner 1- his shelters
Owner 2 - His Shelters
The whole problem is in the controller, what exactly should I pass to the template engine? This is the whole problem, thanks in advance for the answers and time taken
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
#DynamicUpdate
#Entity
#Table(name = "owner")
public class Owner {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int idOwner;
private String name;
private String address;
private String description;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "owner_shelter",
inverseJoinColumns = { #JoinColumn(name = "shelter_id") })
private List<Shelter> shelters = new ArrayList<>();
public void addShelter(Shelter shelter) {
shelters.add(shelter);
shelter.getOwners().add(this);
}
public void removeShelter(Shelter shelter) {
shelters.remove(shelter);
shelter.getOwners().remove(this);
}
}
#Data
#DynamicUpdate
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Entity
#Table(name = "shelter")
public class Shelter {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private String address;
private String description;
#ManyToMany(mappedBy = "shelters")
private List<Owner> owners;
public void addOwner(Owner owner) {
owners.add(owner);
owner.getShelters().add(this);
}
public void removeOwner(Owner owner) {
owners.remove(owner);
owner.getShelters().remove(this);
}
}
now i can print only list of shelter or owner
#Autowired
ShelterRepository shelterRepository;
#Autowired
OwnerRepository ownerRepository;
#GetMapping("/shelters")
public String getPage(Authentication authentication, Model model) {
if (authentication != null) {
model.addAttribute("authentication", authentication);
}
List<Shelter> shelters = shelterRepository.findAll();
List<Owner> owners = ownerRepository.findAll();
model.addAttribute("shelters", shelters);
model.addAttribute("owners", owners);
return "shelterList";
}
Related
I want to implement a simple uni-directional one-to-many association. I have tried the below setup. But when I fetch the Tenant entity, I always see null for the subscriptions field.
#Getter
#Setter
#Entity
#ToString
public class Tenant {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String tenantKey;
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name="tenantKey")
private Set<Subscription> subscriptions;
public Set<Subscription> getSubscriptions() {
return subscriptions;
}
public void setSubscriptions(Set<Subscription> subscriptions) {
this.subscriptions = subscriptions;
}
}
and below is the Subscription entity
#Entity
#Getter
#Setter
#ToString
public class Subscription {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String tenantKey;
private String serviceName;
}
Below is my repository class which I fetch the Tenant object
#ApplicationScoped
public class TenantRepository implements PanacheRepository<Tenant> {
public Uni<Tenant> findByTenantKey(String tenantKey) {
return find("tenantKey= ?1", tenantKey).firstResult();
}
}
so i am trying to set two related object in each other's fields. But when i debug the code i get that after i set the first object as a field in the other i am getting the following error: com.sun.jdi.InvocationException: Exception occurred in target VM occurred invoking method.
Here is the source code, i hope someone can help. Thank you :D
#Service #Transactional
public class MainService {
#Autowired CustomTableRepository tRepo;
#Autowired UserRepository uRepo;
#Autowired ReservationRepository rRepo;
#SneakyThrows
public void reserveTable(Reservation reservation) {
CustomTable table = tRepo.findById(reservation.getTable().getId()).get();
User user = uRepo.findByUsername(reservation.getUser().getUsername());
Reservation myReservation = new Reservation(null, reservation.getAccepted(), user, table, reservation.getTime());
rRepo.saveAndFlush(myReservation);
if(!(reservationRequirements(rRepo.findByUser(user))))
throw new Exception("something went wrong with the reservation, regarding the requierements");
else {
user.setBalance(user.getBalance() - CONSTANTS.fee );
user.setReservation(myReservation);
myReservation.setAccepted(true);
myReservation.setTable(table);
myReservation.setUser(user);
table.setReservation(myReservation);
table.setAvailable(false);
uRepo.saveAndFlush(user);
tRepo.saveAndFlush(table);
rRepo.save(myReservation);
}
}
/*
* PRIVATE HELPING METHODS
*/
private Boolean reservationRequirements(Reservation reservation) {
User user = uRepo.findByUsername(reservation.getUser().getUsername());
//check if the user has enough money
if(user.getBalance() < CONSTANTS.fee)
return false;
//check if they accepted the money fee.
if(reservation.getAccepted() == false)
return false;
//if the table is occupied
if(reservation.getTable().getAvailable() == null) {
}else {
if(reservation.getTable().getAvailable() == false)
return false;
}
LocalTime time = CONSTANTS.parseLocalTime(reservation.getTime());
if(!(time.isAfter(LocalTime.parse("07:30")) && time.isBefore(LocalTime.parse("22:00"))))
return false;
return true;
}
}
This is how they are all related one to other:
Entity classes:
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class CustomTable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Boolean available;
private Boolean busy;
private Boolean arrived;
#OneToOne(mappedBy = "table", cascade = CascadeType.ALL, orphanRemoval = true)
private Reservation reservation;
}
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Reservation {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private Boolean accepted;
#OneToOne
#JoinColumn(name = "user_id")
private User user;
#OneToOne
#JoinColumn(name = "table_id")
private CustomTable table;
private String time;
}
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String type;
}
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String username;
private String password;
private Long number;
private Long balance;
#OneToOne(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private Reservation reservation;
#ManyToMany(fetch = FetchType.EAGER)
private Collection<Role> roles;
}
Thank you a lot for reading.
I'm a beginner in spring boot, try to make an app with class Department & Employee. I make the relation between these two classes, Department can have many Employee whereas Employee can only have one Department. Every time I ended with an error:
com.learning.model.Employee cannot be converted to java.lang.Integer
Also, I've found two ways to inserting data into DB via API. First through the service layer, 2nd directly through the controller. Thankful if you could advise as to what is the most authentic method among the two above.
Department.java
#Entity
#Table(name = "Department")
#Getter
#Setter
#ToString
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
public class Department {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "dept_seq")
#SequenceGenerator(initialValue = 1, name = "dept_seq", sequenceName = "dept_sequence")
#Column(name = "id")
private Integer id;
#Column(name = "deptName")
private String deptName;
#OneToMany(mappedBy = "department", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonIgnore
private List<Employee> employees;
}
Employee.java
#Entity
#Table(name = "Employee_Dtls")
#ToString
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "emp_seq")
#SequenceGenerator(initialValue = 1, name = "emp_seq", sequenceName = "employee_sequence")
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "dept_id")
private Department department;
}
DepartmentService.java
#Service
public class DepartmentService {
#Autowired
private EmployeeRepository employeeRepository;
#Autowired
private DepartmentRepository departmentRepository;
//Get Department
public List<Department> getAllDepartments() {
return departmentRepository.findAll();
}
//Add Department
public Department addDepartment(Department department) {
Employee emp = employeeRepository.findById(department.getEmployees().get(department.getId())).orElse(null);
if (null == emp) {
emp = new Employee();
}
emp.setName(department.getEmployees().get(emp.getId()));
department.setEmployees(emp);
return departmentRepository.save(department);
}
}
DepartmentController.java
public class DepartmentController {
#Autowired
private DepartmentService departmentService;
#GetMapping("/get-departments")
public ResponseEntity<List<Department>> getAllDepartments() {
List<Department> departments = departmentService.getAllDepartments();
return new ResponseEntity<>(departments, HttpStatus.OK);
}
#PostMapping("/department")
public ResponseEntity<Department> saveDepartment(#RequestBody Department department) {
Department dept = departmentService.addDepartment(department);
return new ResponseEntity<>(dept, HttpStatus.OK);
}
}
I think you must go over these stacks, these will probably help you to understand how #onetomany annotation works in spring
One to Many Relationship in spring boot REST Api
POSTing oneToMany in a REST call via Spring Boot API
I have 2 entities, related with #OneToMany.
#Entity
#Table(name = "appeal_templates")
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class AppealTemplate extends AbstractEntity {
private List<Question> questions = new ArrayList<>();
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "template")
public List<Question> getQuestions() {
return questions;
}
}
And second one:
#Setter
#Entity
#Table(name = "appeal_template_questions")
public class Question extends AbstractEntity {
private AppealTemplate template;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "template_id")
public AppealTemplate getTemplate() {
return template;
}
}
AbstractEntity:
#MappedSuperclass
#Setter
#EqualsAndHashCode
#ToString
public abstract class AbstractEntity implements Serializable {
private static final int START_SEQ = 1000;
private Long id;
private LocalDateTime created;
private LocalDateTime updated;
#Id
#SequenceGenerator(name = "global_seq", sequenceName = "global_seq", allocationSize = 1, initialValue = START_SEQ)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "global_seq")
public Long getId() {
return id;
}
#Column(name = "created", updatable = false)
public LocalDateTime getCreated() {
return created;
}
#Column(name = "updated", insertable = false)
public LocalDateTime getUpdated() {
return updated;
}
#PrePersist
public void beforeCreate() {
if (Objects.isNull(created)) {
created = LocalDateTime.now();
}
}
#PreUpdate
public void beforeUpdate() {
if (Objects.isNull(updated)) {
updated = LocalDateTime.now();
}
}
}
I send dto to save like this:
AppealTemplate(id=null, questions=[Question(id=null, initial=false, rank=null, text=Quo vadis?)])
ID not filled while they not sved, both entities saving by AppealTemplate repository, but for Question field template_id not filled.
How to do that template_id filled automatically with first save?
I'm trying to get Hibernate #OneToOne annotation working with 2 classes, Hito and Portada. Portada table has the foreign key of Hito, an int attribute called hito.
My entities looks like this:
Hito:
#Entity
#Table(name = "hito")
public class Hito implements Serializable {
//...other attributes
private Portada portada;
//...getters and setters from other attributes
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "hito")
public Portada getPortada(){ return portada;}
public void setPortada(Portada portada){ this.portada = portada;}
}
Portada:
#Entity
#Table(name = "portada")
public class Portada {
//...other attributes
private Hito hito;
//...getters and setters from other attributes
#OneToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "hito")
public Hito getHito() {return hito;}
public void setHito(Hito hito) {this.hito = hito;}
}
When I call hito.getPortada(), I expect a Portada object, but it returns null.
Any suggestions?
I tried to reproduce your problem with code:
#MappedSuperclass
public abstract class BaseEntity {
#Id #GeneratedValue
private Long id;
#Version
private long version;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
}
#Entity
#Table(name = "portada")
public class Portada extends BaseEntity {
//...other attributes
#OneToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "hito")
private Hito hito;
//...getters and setters from other attributes
public Hito getHito() {return hito;}
public void setHito(Hito hito) {this.hito = hito;}
}
#Entity
#Table(name = "hito")
public class Hito extends BaseEntity implements Serializable {
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "hito")
private Portada portada;
public Portada getPortada(){ return portada;}
public void setPortada(Portada portada){ this.portada = portada;}
}
// app:
Portada p = new Portada();
Hito h = new Hito();
p.setHito(h);
h.setPortada(p);
entityManager.persist(h);
entityManager.flush();
entityManager.clear();
Hito h2 = entityManager.find(Hito.class, h.getId());
System.out.println(h2.getPortada().toString());
tx.commit();
The last find generated sql:
select
hito0_.id as id1_4_0_,
hito0_.version as version2_4_0_,
portada1_.id as id1_7_1_,
portada1_.version as version2_7_1_,
portada1_.hito as hito3_7_1_
from
hito hito0_
left outer join
portada portada1_
on hito0_.id=portada1_.hito
where
hito0_.id=?
Everything worked for me...
EDIT: Only difference is that I like to put mapping attributes on fields instead of properties but it doesn't matter in this problem. Please check if you add both of your classes to persistance.xml or hibernate config.