Hibernate nulls in DB with #Embedded - java

hello im learning Hibernate, currently I'm trying to use #Embedded annotation, but i got nulls from #Embeddable object in my DB.
the code is as follows:
#Entity
public class Employee {
#Id
#GeneratedValue
private int id;
private String firstName;
private String lastName;
private double salary;
#Embedded
private Adress adress;
public Adress getAdress() {
return adress;
}
public void setAdress(Adress adress) {
this.adress = adress;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
So that is my Employee class which hold, #embedded field from Adress.class
Here comes Adress class:
#Embeddable
public class Adress {
private String locality;
private String streetNumber;
private String zipCode;
public String getLocality() {
return locality;
}
public void setLocality(String locality) {
this.locality = locality;
}
public String getStreetNumber() {
return streetNumber;
}
public void setStreetNumber(String streetNumber) {
this.streetNumber = streetNumber;
}
public String getZipCode() {
return zipCode;
}
public void setZipCode(String zipCode) {
this.zipCode = zipCode;
}
}
and thats my main class:
public class Main {
public static void main(String[] args) {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myDatabase");
EntityManager entityManager = entityManagerFactory.createEntityManager();
Employee employee = new Employee();
Adress adress = new Adress();
adress.setLocality("New York");
adress.setZipCode("55-5555");
adress.setStreetNumber("55");
employee.setFirstName("Andy");
employee.setLastName("Cole");
employee.setSalary(3333);
entityManager.getTransaction().begin();
entityManager.persist(employee);
entityManager.getTransaction().commit();
entityManager.close();
entityManagerFactory.close();
}
}
So fields related to class Employee go to the database without problem, but fields related to class Adress are set to null. I'd like to have them as setValues. Thanks in advance to all.

You're missing setAddress call
public class Test {
public static void main(String[] args) {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("myDatabase");
EntityManager entityManager = entityManagerFactory.createEntityManager();
Employee employee = new Employee();
Adress adress = new Adress();
adress.setLocality("New York");
adress.setZipCode("55-5555");
adress.setStreetNumber("55");
employee.setFirstName("Andy");
employee.setLastName("Cole");
employee.setSalary(3333);
employee.setAdress(adress);
entityManager.getTransaction().begin();
entityManager.persist(employee);
entityManager.getTransaction().commit();
entityManager.close();
entityManagerFactory.close();
}
}

You need to set your created Adress object in your employee before persisting the employee, as in your current implementation your employee is not aware of his adress.
employee.setAdress(adress);

Related

Spring Boot H2 returns empty list on findAll()

When I try to use the getAllPeople() and getEmployeeById(), I get an empty list and a blank screen respectively.
All the solutions I have looked into so far have given me no results.
I have a database with just one table:
This is my application.properties:
spring.datasource.url=jdbc:h2:mem:person;DB_CLOSE_DELAY=-1
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.defer-datasource-initialization=true
This is my model:
#Entity
#Table(name="PERSON")
public class PersonEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Long id;
#Column(name="first_name")
public String firstName;
#Column(name="last_name") public String lastName;
#Column(name="city") public String city;
#Column(name="state1") public String state1;
#Column(name="zip") public int zip;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getState() { return state1; }
public void setState(String state) { this.state1 = state; }
public int getZip() { return zip; }
public void setZip(int zip) { this.zip = zip; }
}
This is my repository:
import org.springframework.data.jpa.repository.JpaRepository;
import com.walmart.demo.model.*;
public interface PersonRepository extends JpaRepository<PersonEntity, Long> {
}
This is my service:
#Service
public class PersonService {
#Autowired
PersonRepository personRepository;
public PersonEntity createOrUpdateEmployee(PersonEntity entity) {
Optional<PersonEntity> employee = personRepository.findById(entity.getId());
if (employee.isPresent()) {
PersonEntity newEntity = employee.get();
newEntity.setFirstName(entity.getFirstName());
newEntity.setLastName(entity.getLastName());
newEntity.setCity(entity.getCity());
newEntity.setState(entity.getState());
newEntity.setZip(entity.getZip());
newEntity = personRepository.save(newEntity);
return newEntity;
} else {
entity = personRepository.save(entity);
return entity;
}
}
public List<PersonEntity> getAll() {
List<PersonEntity> personList = personRepository.findAll();
if (personList.size() > 0) {
return personList;
} else {
return new ArrayList<PersonEntity>();
}
}
public PersonEntity getPersonById(Long id) {
Optional<PersonEntity> person = personRepository.findById(id);
if (person.isPresent()) {
return person.get();
}
return null;
}
}
This is my controller:
#RestController
public class PersonController {
#Autowired
PersonService service;
#RequestMapping(value = "/person", method = RequestMethod.POST)
public ResponseEntity<PersonEntity> createOrUpdateEmployee(PersonEntity employee) {
PersonEntity updated = service.createOrUpdateEmployee(employee);
return new ResponseEntity<>(updated, new HttpHeaders(), HttpStatus.OK);
}
#RequestMapping(value = "/people", method = RequestMethod.GET)
public ResponseEntity<List<PersonEntity>> getAllEmployees() {
List<PersonEntity> list = service.getAll();
return new ResponseEntity<>(list, new HttpHeaders(), HttpStatus.OK);
}
#RequestMapping(value = "/people/{id}", method = RequestMethod.GET)
public ResponseEntity<PersonEntity> getEmployeeById(#PathVariable("id") Long id) {
PersonEntity entity = service.getPersonById(id);
return new ResponseEntity<>(entity, new HttpHeaders(), HttpStatus.OK);
}
}
Specify a file instead of memory in your application.properties:
spring.datasource.url=jdbc:h2:file:~/person;DB_CLOSE_ON_EXIT=FALSE;

Hibernate OneToOne relationship

I have 3 classes Appointment,Patient and Doctor.Appointment have 1to1 reletionship with both Patient and Doctor.
When i insert a appointment object in database everytime the new patient and doctor object is also inserted in the database.
Patient Class:
#Entity
#Table(name = "Patient")
public class Patient {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private int patientId;
private String firstName;
private String lastName;
private int age;
private String cnic;
private String contactNumber;
private String homeNumber;
private String country;
private String city;
private String town;
private String streetNo;
private String houseNo;
private String email;
private String username;
private String password;
public int getPatientId() {
return patientId;
}
public void setPatientId(int patientId) {
this.patientId = patientId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getCnic() {
return cnic;
}
public void setCnic(String cnic) {
this.cnic = cnic;
}
public String getContactNumber() {
return contactNumber;
}
public void setContactNumber(String contactNumber) {
this.contactNumber = contactNumber;
}
public String getHomeNumber() {
return homeNumber;
}
public void setHomeNumber(String homeNumber) {
this.homeNumber = homeNumber;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getTown() {
return town;
}
public void setTown(String town) {
this.town = town;
}
public String getStreetNo() {
return streetNo;
}
public void setStreetNo(String streetNo) {
this.streetNo = streetNo;
}
public String getHouseNo() {
return houseNo;
}
public void setHouseNo(String houseNo) {
this.houseNo = houseNo;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getId(){
return patientId;
}
public Patient getPatient(){
return this;
}
}
Doctor Class :
#Entity
#Table(name = "Doctor")
public class Doctor extends Users {
private String specialization;
public String getSpecialization() {
return specialization;
}
public void setSpecialization(String specialization) {
this.specialization = specialization;
}
}
Appointment Class:
#Entity
public class AppointmentClass {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private int appointmentId;
private int appointmentDay;
private int appointmentTime;
#OneToOne (cascade=CascadeType.ALL,fetch = FetchType.EAGER)
private Patient patient;
#OneToOne (cascade=CascadeType.ALL,fetch = FetchType.EAGER)
private Doctor doctor;
public int getAppointmentId() {
return appointmentId;
}
public void setAppointmentId(int appointmentId) {
this.appointmentId = appointmentId;
}
public int getAppointmentDay() {
return appointmentDay;
}
public void setAppointmentDay(int appointmentDay) {
this.appointmentDay = appointmentDay;
}
public int getAppointmentTime() {
return appointmentTime;
}
public void setAppointmentTime(int appointmentTime) {
this.appointmentTime = appointmentTime;
}
public Patient getPatient() {
return patient;
}
public void setPatient(Patient patient) {
this.patient = patient;
}
public Doctor getDoctor() {
return doctor;
}
public void setDoctor(Doctor doctor) {
this.doctor = doctor;
}
}
Service Class:
public class AppointmentPatientService {
private SessionFactory sessionFactory = null;
public AppoinmentPatient createNewAppointment(AppoinmentPatient appointment){
try{
sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
Patient patient = new Patient();
Doctor doctor = new Doctor();
patient = (Patient)(appointment).getPatient();
AppointmentClass appointment1 = new AppointmentClass();
appointment1 = (AppointmentClass)(appointment).getAppointment();
doctor = (Doctor)appointment.getDoctor();
appointment1.setPatient(patient);
appointment1.setDoctor(doctor);
session.beginTransaction();
session.save(appointment1);
session.getTransaction().commit();
session.close();
}catch(Exception ex){
ex.printStackTrace();
}
return appointment;
}
}
Is there any way that when i save the appointment object the new objects of patient and doctor not save to the database.
I shall be thankful :)
I think your relationship type should not be OneToOne from neither the doctor or the patient, because one doctor can have many appointments and one patient can have many appointments. So it should be OneToMany from both sides, in which case a new doctor and a new patient won't be created for each new appointment if you supply the appointment with correct existing doctor and patient ID-s.
In the class AppointmentClass, change the cascade settings.
You can use cascade=CascadeType.NONE, This will make sure that the associated Patient and Doctor objects are not saved to database.
You can see all other values of CascadeType to find the right choice for you.

What are the constraints in using constructors in POJO while using hibernate?

I was trying a simple hibernate populate the db example. There are two POJO's Employee and Address. When I tried to use both the Employee and Address constructor's with parameters to create two instances an error could not get constructor for org.hibernate.persister.entity.singletableentitypersisterwas thrown but the property accessor methods worked fine. Why did I get the error ?
Ok since I do not have the stack trace right now I shall rephrase my question are property accessor methods preferred over constructors in hibernate?
Employee POJO:
package many2one;
public class Employee {
public int id;
public String firstName;
public String lastName;
public int salary;
public Address address;
public Employee(){}
public Employee(String firstName,String lastName,int salary,Address address){
this.firstName = firstName;
this.lastName = lastName;
this.salary = salary;
this.address = address;
}
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getFirstName(){
return firstName;
}
public void setFirstName(String fname){
this.firstName = fname;
}
public String getLastName(){
return lastName;
}
public void setLastName(String lname){
this.lastName = lname;
}
public int getSalary(){
return salary;
}
public void setSalary(int salary){
this.salary = salary;
}
public Address getAddress(){
return address;
}
public void setAddress(Address address){
this.address = address;
}
#Override
public String toString(){
return id+","+firstName+","+lastName+","+salary+","+address.getStreetName()+","+address.getCityName()+","+address.getStateName()+","+address.getZipcode();
}
}
Address POJO:
package many2one;
public class Address {
public int id;
public String streetName;
public String cityName;
public String stateName;
public String zipcode;
public Employee employee;
public Address(){
}
public Address(String sname,String cname,String statename,String zipcode){
this.streetName = sname;
this.cityName = cname;
this.stateName = statename;
this.zipcode = zipcode;
}
public int getId(){
return id;
}
public void setId(int id){
this.id = id;
}
public String getStreetName(){
return streetName;
}
public void setStreetName(String streetname){
this.streetName = streetname;
}
public String getCityName(){
return cityName;
}
public void setCityName(String cname){
this.cityName = cname;
}
public String getStateName(){
return stateName;
}
public void setStateName(String statename){
this.stateName = statename;
}
public String getZipcode(){
return zipcode;
}
public void setZipcode(String zipcode){
this.zipcode = zipcode;
}
public Employee getEmployee(){
return employee;
}
public void setEmployee(Employee employee){
this.employee = employee;
}
}
`
Your class should have a default public constructor that does not take any arguments. That's the only constraint with respect to constructors when using Hibernate.
As for the exception, you are probably missing a setter for one of your fields or the setters don't follow the convention expected by Hibernate. But this can only be confirmed if you provide a full stack trace.
are property accessor methods preferred over constructors in
hibernate?
What do you mean by preffered? If you mean are property methods optional, then the answer is no. (Whcih could be one of the reasons for the exception in the first place)

JPA with composite key and secondary table

I'm new to JPA an I have a problem when trying to work with a secondary table and a composite key.
I get the following error message when I try to add, delete or update:
Provided id of the wrong type Expected: class EmployeePK, got class
java.lang.Integer
#Entity
#IdClass(EmployeePK.class)
#Table(name="specialemployee")
#SecondaryTable(name = "employeeTypeAndSalary", pkJoinColumns = {
#PrimaryKeyJoinColumn(name = "employee_Id"),
#PrimaryKeyJoinColumn(name = "employee_Email") })
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
public enum EmployeeType {
WORKER, FOREMAN, MANAGEMENT
}
#Id
private int id;
#Column(name = "EMP")
#Embedded
private Name name;
#Id
private String email;
private Date birthDate;
#Lob
private String comments;
#Column(name = "EMP_SALARY", table = "employeeTypeAndSalary")
private double salary;
#Column(name = "EMP_TYPE", table = "employeeTypeAndSalary")
#Enumerated(EnumType.STRING)
private EmployeeType employeeType;
public Employee() {
super();
}
public Employee(int id, Name name, String email, double salary, String birthDate,
String comments, EmployeeType employeeType) {
super();
this.id = id;
this.name = name;
this.email = email;
this.salary = salary;
try {
this.birthDate = java.sql.Date.valueOf(birthDate);
} catch (Exception e) {
logging.error("error on creating date" + " :" + e);
this.birthDate = java.sql.Date.valueOf("1900-00-00");
}
this.comments = comments;
this.employeeType = employeeType;
}
//getters and setters
}
public class EmployeePK implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String email;
// non-arg default constructor
public EmployeePK() {
super();
}
public EmployeePK(int id, String email){
this.id = id;
this.email = email;
}
public int getId() {
return id;
}
protected void setId(int id) {
this.id = id;
}
public String getEmail() {
return email;
}
protected void setEmail(String email) {
this.email = email;
}
public boolean equals(Object o) {
return ((o instanceof EmployeePK) &&
email.equals(((EmployeePK)o).getEmail()) &&
id == ((EmployeePK) o).getId());
}
public int hashCode() {
return (int) (email.hashCode() + id);
}
}
#Embeddable
public class Name implements Serializable {
private static final long serialVersionUID = 1L;
private String firstName;
private String lastName;
public Name() {
super();
}
#Override
public String toString() {
return "Name [firstName=" + firstName + ", lastName=" + lastName + "]";
}
public Name(String firstName, String lastName) {
super();
this.firstName = firstName;
this.lastName = lastName;
}
// getters and setters
}
I have been looking at it for some time now and I don't see what I'm doing wrong. Any advice would be welcome.
Thanks.
Edited :
Name name1 = new Name("Johnn", "Doe");
Employee employee1 = new Employee(1, name1, "employee1#hotmail.com",
1857.87, "1976-05-12", "ready for promotion",
EmployeeType.MANAGEMENT);
addEmployee(employee1);
private static void addEmployee(Employee employee) {
EntityManagerFactory emf = Persistence
.createEntityManagerFactory("JPA_excercise");
EntityManager em = emf.createEntityManager();
try {
em.getTransaction().begin();
em.persist(employee);
em.getTransaction().commit();
} catch (Exception e) {
logging.error("This error has occured when adding a employee"
+ " :" + e);
} finally {
em.close();
emf.close();
}
}
Problem found. Add method didn't had any problems. Issue in update method where I forgot to change the logging text so it seemed that the problem whas in teh add method. Issue solved

Customized JAXB xml output

Given the following class:
public class Customer {
public String name;
public String lastName;
}
I want to generate the following xml output using JAXB for a customer whose name is John and lastName is Doe:
<cst>John Doe</cst>
How can i do this with JAXB?
EDIT
The class Customer is used in several places, as shown here:
public class Sale {
private String productId;
private Date date;
private Customer customer;
}
public class Transaction {
private List<Sale> sales;
}
... and so on... The deal is, how can I tell JAXB: "whenever you see a customer, please use custom formatting"?
My problem is that there are many classes that contain a customer, and I want to programatically control the output (sometimes name + lastname, sometimes <name>name</name>, <lastname>lastname</lastname>) without adding annotations at every class that contains Customer. This requirement would rule out using JAXBElement<Customer>.
You could install an XmlAdapter that handles the translation:
public static void main(String[] args) throws Exception {
JAXBContext ctxt = JAXBContext.newInstance(CustomerWrapper.class);
Marshaller m = ctxt.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
Customer customer = new Customer("John", "Doe");
m.marshal(new JAXBElement<CustomerWrapper>(new QName("cwrapper"), CustomerWrapper.class, new CustomerWrapper(customer)), System.err);
}
static class CustomerWrapper {
private Customer customer;
public CustomerWrapper() {
}
public CustomerWrapper(Customer customer) {
this.customer = customer;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
#XmlJavaTypeAdapter(CustomerAdapter.class)
static class Customer {
private String name;
private String lastName;
public Customer() {
}
public Customer(String name, String lastName) {
this.name = name;
this.lastName = lastName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
static class CustomerAdapter extends XmlAdapter<String, Customer> {
#Override
public Customer unmarshal(String v) throws Exception {
String[] ss = v.split(" ");
return new Customer(ss[0], ss[1]);
}
#Override
public String marshal(Customer v) throws Exception {
return v.getName() + " " + v.getLastName();
}
}
outputs
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cwrapper>
<customer>John Doe</customer>
</cwrapper>

Categories