I can not seems to get hibernate to grab any info from mySQL. I've read everywhere and I feel I am doing this correct, apparently I'm not but my brain has blew trying to understand what I messed up.
Main:
#SpringBootApplication
#ComponentScan("com.luv2code")
#EntityScan("com.luv2code.entity")
#EnableJpaRepositories("com.luv2code.dao")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Controller:
#Controller
public class CustomerController {
private CustomerDAO customerDAO;
#Autowired
public void setCustomerDAO(CustomerDAO customerDAO) {
this.customerDAO = customerDAO;
}
#RequestMapping("/")
public String listCustomers(Model model){
long test = customerDAO.count();
model.addAttribute("answer", test);
List<Customer> customers = customerDAO.findAll();
model.addAttribute("customers", customers);
return "home";
}
}
application.properties:
spring.datasource.url = jdbc:mysql://localhost:3306/web_customer_tracker?useSSL=false
spring.datasource.username=root
spring.datasource.password=metalgear3
spring.datasouce.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.show-sql=true
spring.jpa.hibernate.dialect=org.hibernate.dialect.MySQL55Dialect
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext
entitymanager.packagesToScan = com.luv2code.entity.Customer
Entity:
#Entity
#Table(name = "customer")
public class Customer implements Serializable {
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
private int id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "email")
private String email;
public Customer(){}
#Override
public String toString() {
return "Customer{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
'}';
}
public Customer(String firstName, String lastName, String email){
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
DAO:
#Repository("CustomerDAO")
#Transactional
public interface CustomerDAO extends CrudRepository<Customer, Integer> {
public List<Customer> findAll();
public long count();
}
MySql:
CREATE DATABASE IF NOT EXISTS `web_customer_tracker`;
USE `web_customer_tracker`;
DROP TABLE IF EXISTS `customer`;
CREATE TABLE `customer`(
`id` INT(11) NOT NULL auto_increment,
`first_name` VARCHAR(45) DEFAULT NULL,
`last_name` VARCHAR(45)DEFAULT NULL,
`email` VARCHAR(45) DEFAULT NULL,
PRIMARY KEY(`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 CHARSET=latin1;
INSERT INTO `customer` VALUES
(1, 'David', 'Adams', 'david#luv2code.com'),
(2, 'John', 'Die', 'john#luv2code.com'),
(3, 'Ajay', 'Rao', 'ajay#luv2code.com'),
(4, 'Mary', 'Publiidc', 'mary#luv2code.com'),
(5, 'Maxwell', 'Dixon', 'maxwell#luv2code.com');
I know it's a bit late to respond, but this questions is google friendly.
You don't need to declare findAll() inside CustomerDAO. The interface CrudRepository already does it. On top of that, I recommend implementing JpaRepository repository instead (which extends CrudRepository itself and gives you way more convenience methods for free.
Related
I am working on a Spring Boot project and decided to use MongoDB . I just want to generate sequence number in MongoDB. So even if 100s of different clients trying to do that, I do not want to conflict any generated number. Is there any way to do that ?
Also I tried to make something like this :
SequenceNumber sequenceNumber;
String SEQUENCE_NAME = "example";
sequenceNumber = mongoOperations.findAndModify(query(where("_id").is(SEQUENCE_NAME)),
new Update().inc("number", 1), options().returnNew(true).upsert(true),
SequenceNumber.class);
return sequenceNumber.getNumber();
Is this correct ?
Thanks for answers !
https://www.javaprogramto.com/2019/05/spring-boot-mongodb-auto-generated-field.html
First, create a collection that will store the auto-incremented value in it. This can be created using either the mongo shell or MongoDB Compass
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection = "database_sequences")
public class DatabaseSequence {
#Id
private String id;
private long seq;
public DatabaseSequence() {}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public long getSeq() {
return seq;
}
public void setSeq(long seq) {
this.seq = seq;
}
}
Let’s then create a users_db collection. This collection stores the users that are being used.
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection = "users_db")
public class User {
#Transient
public static final String SEQUENCE_NAME = "users_sequence";
#Id
private long id;
private String firstName;
private String lastName;
private String email;
public User() { }
public User(String firstName, String lastName, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
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 getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Override
public String toString() {
return "User{" + "id=" + id + ", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' + ", email='" + email + '\'' + '}';
}
I am facing issue in querying repository with find all by child object ID, Example and Pageable.
StudentController.java
#RestController
#RequestMapping("/students")
public class StudentController {
#Autowired
private StudentService studentService;
#RequestMapping(method = RequestMethod.GET)
public Page<Student> getStudentsPage(
#PageableDefault(page = 0, size = 10) #SortDefault.SortDefaults({
#SortDefault(sort = "id", direction = Direction.DESC) }) Pageable pageable,
Student student) {
return studentService.getStudentPage(student, pageable);
}
}
StudentService.java
#Service
public class StudentService {
private static final Logger logger = LoggerFactory.getLogger(StudentService.class);
#Autowired
private UserService userService;
#Autowired
private StudentRepository studentRepository;
public Page<Student> getStudentsPage(Student student, Pageable pageable) {
logger.debug("Getting Students : {}, {}", student, pageable);
//gets organization Id of the student from the session
String organizationId = userService.getUserMe().getOrganization().getId();
Page<Student> studentPage = studentRepository.findAllByOrganizationId(organizationId, Example.of(student), pageable);
logger.debug("Students: {}", studentPage.getContent());
return studentPage;
}
}
StudentRepository.java
#Repository
public interface StudentRepository extends MongoRepository<Student, String> {
Page<Student> findAllByOrganizationId(String organizationId, Example<Student> example, Pageable pageable);
}
Student.java
#Document(collection = "students")
public class Student {
#Id
private String id;
private String firstName;
private String lastName;
#DBRef(db = "organizations")
private Organization organization;
public String getId() {
return id;
}
public void setId(String 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 Organization getOrganization() {
return organization;
}
public void setOrganization(Organization organization) {
this.organization = organization;
}
#Override
public String toString() {
return "Student [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", organization="
+ organization + "]";
}
}
Organization.java
#Document(collection = "organizations")
public class Organization {
#Id
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "Organization [id=" + id + ", name=" + name + "]";
}
}
The GET API request:
http://localhost:8080/students?page=0&size=10&sort=id,desc&lastName=xyz
the repository method
Page findAllByOrganizationId(String organizationId, Example example, Pageable pageable);
should return all the records with matching organizationId and lastName=xyz, But it returns the records that match with the organization Id along with all the students irrespective of the lastName.
Is something wrong with the code?
Finally found answer.
findBy and Example Executor doesn't work together.
By setting the child object filter and query by Example Executor as shown below.
public Page<Student> getStudentsPage(Student student, Pageable pageable) {
logger.debug("Getting Students : {}, {}", student, pageable);
//gets organization Id of the student from the session
String organizationId = userService.getUserMe().getOrganization().getId();
student.setOrganization(new Organization(organizationId));
Page<Student> studentPage = studentRepository.findAll(Example.of(student), pageable);
logger.debug("Students: {}", studentPage.getContent());
return studentPage;
}
This works as expected!!
Thanks!!
I have Entity with 3 fields: id, lastname and phoneNumber. I want to create method which works for update all fields or only one or two.
I use Hibernate and JPA Repository.
When I try to update all fields everything works well but when for example i want to update only lastname without changing of phoneNumber I have in output null insted of old phoneNumber.
Here is my method from Controller:
#PutMapping("/students/update/{id}")
public String updateStudentById(#ModelAttribute Student student, #ModelAttribute StudentDetails studentDetails,
String lastname, String phoneNumber,
#PathVariable Long id) {
Optional<Student> resultOptional = studentRepository.findById(id);
//Student result =resultOptional.get();
resultOptional.ifPresent((Student result) -> {
result.getStudentDetails().setPhoneNumber(studentDetails.getPhoneNumber()); result.getStudentDetails().setLastname(studentDetails.getLastname());
studentRepository.save(result);
});
return "Student updated";
}
The class for update:
#DynamicUpdate
#Entity
public class StudentDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="lastname")
private String lastname;
#Column(name="phone_number")
private String phoneNumber;
public StudentDetails() {
}
public StudentDetails(Long id, String lastname, String phoneNumber) {
this.id = id;
this.lastname = lastname;
this.phoneNumber = phoneNumber;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
The class which has relation with StudentDetails:
#Entity
#Table(name = "student")
#DynamicUpdate
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
//#OneToMany(mappedBy = "student")
#ManyToMany
#JoinTable(name="course_student",joinColumns = #JoinColumn(name="student_id"),
inverseJoinColumns = #JoinColumn(name="course_id"))
private List<Courses> courses;
#OneToOne(cascade = CascadeType.ALL)
// #JoinColumn(name="studen/_details_id") // with this we have dobule student_details column
private StudentDetails studentDetails;
public List<Courses> getCourses() {
return courses;
}
public void setCourses(List<Courses> courses) {
this.courses = courses;
}
public StudentDetails getStudentDetails() {
return studentDetails;
}
public void setStudentDetails(StudentDetails studentDetails) {
this.studentDetails = studentDetails;
}
// Methods for StudentViewController
public String getLastname(){
return studentDetails.getLastname();
}
public String getPhoneNumber(){
return studentDetails.getPhoneNumber();
}
public Student() {
}
public Student(String name, String email, StudentDetails studentDetails) {
// this.id = id;
this.name = name;
this.email = email;
this.studentDetails = studentDetails;
}
public Long getId() {
return id;
}
public void setId(Long 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;
}
#Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", email='" + email + '\'' +
'}';
}
}
I was looking for solution and I added #DynamicUpdate but still it doesn't work.
Your code works properly. When you only provide lastName parameter in your request, then the phoneNumber parameter will be mapped to null so you override the phoneNumer property in your entity with this null value.
Change the code in the following way:
resultOptional.ifPresent((Student result) -> {
if(studentDetails.getPhoneNumber()!=null) {
result.getStudentDetails().setPhoneNumber(studentDetails.getPhoneNumber());
}
if(studentDetails.getLastname()!=null) {
result.getStudentDetails().setLastname(studentDetails.getLastname());
}
studentRepository.save(result);
});
Unfortunately it raises an other problem: How will you delete these fields? (How can you set them explicitly to null? )
A possible solution if you check for the "" (empty string) and set the property to null if the parameter is empty string.
It will be a quite messy code anyway...
You should consider using the Spring Data Rest package. It automatically creates all of the standard REST endpoints for your entities and handles all of these PUT/PATCH/POST/DELETE issues out of the box.
why don't you just set the params of your request in you setters?
resultOptional.ifPresent((Student result) -> {
result.getStudentDetails().setPhoneNumber(phoneNumber);
result.getStudentDetails().setLastname(lastname);
studentRepository.save(result);
});
You forget set #OneToOne mapping in StudentDetails - StudentDetails also need field of type Student which will be annotated #OneToOne.
Also you have to ensure, that all of entity fields will be filled - read more about fetch types.
I'm experiencing some difficulties with generating tables in the database through JPA and Hibernate annotations.
When the below code is executed it generates the tables with the following EER diagram.
This is not how I want it to generate the tables.
First of all the relations between the tables are wrong, they need to be OneToOne and not OneToMany.
Secondly, i don't want email to be the primary key in student and teacher.
In Student the ovNumber should be primary key and in Teacher the employeeNumber
I have tried doing it with the #Id annotation but that gives me the following error:
org.hibernate.mapping.JoinedSubclass cannot be cast to org.hibernate.mapping.RootClass
When i try to use #MappedSuperClass the table person does not generate, even when using #Inheritance(strategy=InheritanceType.TABLE_PER_CLASS).
Now my question,
How do I make another variable in subclasses the primary key for the corrosponding table whilst keeping the superclass primary key as foreign key?
How do I fix the relationship between the tables to be an OneToOne relation rather than a OneToMany relation?
Here is an EER diagram of how it should be.
Below are the model classes that are used to generate the tables.
Person.java
#Entity
#Polymorphism(type=PolymorphismType.IMPLICIT)
#Inheritance(strategy=InheritanceType.JOINED)
public class Person implements Comparable<Person>, Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="email", length=64, nullable=false)
private String email;
#Column(name="firstName", length=255)
private String firstName;
#Column(name="insertion", length=255)
private String insertion;
#Column(name="lastName", length=255)
private String lastName;
public Person() {}
/**
* constructor with only email.
*
* #param email
*/
public Person(String email) {
this.email = email;
}
/**
* #param email
* #param firstName
* #param insertion
* #param lastName
*/
public Person(String email, String firstName, String insertion, String lastName){
this.setEmail(email);
this.setFirstName(firstName);
this.setInsertion(insertion);
this.setLastName(lastName);
}
//getters and setters
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getInsertion() {
return insertion;
}
public void setInsertion(String insertion) {
this.insertion = insertion;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Override
public int compareTo(Person o) {
return email.compareTo(o.getEmail());
}
}
Teacher.java
#Entity
#Table(name="teacher")
#PrimaryKeyJoinColumn(name="email", referencedColumnName="email")
public class Teacher extends Person {
private static final long serialVersionUID = 1L;
//this needs to be the pk of teacher table
//#Id
#Column(name="employeeNumber", length=6, nullable=false)
private int employeeNumber;
#Column(name="abbreviation", length=6)
private String abbreviation;
public Teacher(){}
/**
* #param employeeNumber
* #param email
* #param firstName
* #param insertion
* #param lastName
*/
public Teacher(int employeeNumber, String email, String firstName, String insertion, String lastName){
super(email, firstName, insertion, lastName);
this.employeeNumber = employeeNumber;
setAbbreviation();
}
public String getAbbreviation() {
return abbreviation;
}
public void setAbbreviation() {
this.abbreviation = getLastName().substring(0, 4).toUpperCase() + getFirstName().substring(0, 2).toUpperCase();
}
public void setAbbreviation(String abbreviation){
this.abbreviation = abbreviation;
}
public int getEmployeeNumber() {
return employeeNumber;
}
public void setEmployeeNumber(int employeeNumber) {
this.employeeNumber = employeeNumber;
}
#Override
public String toString() {
return "Teacher [abbreviation=" + abbreviation + ", employeeNumber=" + employeeNumber + "]";
}
}
Student.java
#Entity
#Table(name="student")
#PrimaryKeyJoinColumn(name="email", referencedColumnName="email")
public class Student extends Person {
private static final long serialVersionUID = 1L;
#Column(name="cohort")
private int cohort;
//FIXME this needs to be the pk of student table
//#Id
#Column(name="ovNumber", nullable=false)
private int studentOV;
public Student(){}
public Student(int studentOV, int cohort, String email, String firstName,
String insertion, String lastName) {
super(email, firstName, insertion, lastName);
this.studentOV = studentOV;
this.cohort = cohort;
}
public int getCohort() {
return cohort;
}
public void setCohort(int cohort) {
this.cohort = cohort;
}
public int getStudentOV() {
return studentOV;
}
public void setStudentOV(int studentOV) {
this.studentOV = studentOV;
}
#Override
public int compareTo(Person o) {
return getEmail().compareTo(o.getEmail());
}
#Override
public String toString() {
return "Student [firstName=" + getFirstName() + ", insertion=" + getInsertion() + ", lastName=" + getLastName() + ", email="
+ getEmail() + ", cohort=" + getCohort() + ", studentOV=" + getStudentOV() + "]";
}
}
Your goal is to implement inheritance, where Person is your superclass. Teacher and Student are subclasses of that. Inheritance in JPA is not like it's sql-implementation. I advice to read following answer I wrote a while ago. Also read JavaEE 7 - Entity Inheritance Tutorial.
##EDIT##
Here is the solution with different primary keys for each entity for what u asked, still I think that is unusual design (for others please refer to original message):
Person:
#Entity
public class Person implements Serializable {
#Id
#Column
private String email;
#OneToOne(mappedBy = "person")
private Teacher teacher;
#OneToOne(mappedBy = "person")
private Student student;
//more fields
}
Teacher
#Entity
public class Teacher implements Serializable {
#Id
#Column
private Integer employeeNumber;
//constrained to have to be assigned to a Person
//remove constraints if not needed
#OneToOne(optional = false)
#JoinColumn(unique = true, nullable = false)
private Person person;
//more fields
}
Student
#Entity
public class Student implements Serializable {
#Id
#Column
private Integer ovNumber;
//constrained to have to be assigned to a Person
//remove constraints if not needed
#OneToOne(optional = false)
#JoinColumn(unique = true, nullable = false)
private Person person;
//more fields
}
##Original Message##
For your problem I suggest to remodel your jpa-entities. Declare Person as an abstract Entity, extend Teacher and Student by Person.
examplecode:
Person
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "PERSON_TYPE")
public abstract class Person implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private Integer id;
//add your needed fields
}
Teacher and Student respectively
#Entity
public class Teacher extends Person {
//no ID needed, it inherits the id of Person
}
try this in Teacher and Student
#OneToOne
#PrimaryKeyJoinColumn(name="person_email", referencedColumnName="email")
private Person preson;
instead of :
#PrimaryKeyJoinColumn(name="email", referencedColumnName="email")
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