How to write query for many to one mapped entity in JpaRepository - spring

I have two entities and mapped those using many-to-one annotation but after writing a query for find object using another table id I got an error when I commented out that line and method called to that application work but I want to implement that functionality and please help me
These are my entity classes:
#Entity
#Table(name = "Contract")
public class Contract implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "contractId")
private long contractId;
#Column(name="start_date")
private Date st_date;
#Column(name="end_date")
private Date end_date;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "hotel_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Hotel hotel;
// getters and setters
Second entity
#Entity
#Table(name="Hotel")
public class Hotel {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="hotel_id")
private long hotel_id;
#Column(name="hotel_name")
private String hotel_name;
#Column(name="hotel_location")
private String hotel_location;
#Column(name="hotel_email")
private String hotel_email;
#Column(name="hotel_telephone")
private String hotel_telephone
// getters and setters
My contract service class
#Service
public class ContractService {
#Autowired
private ContractRepository contractRepository;
#Autowired
private HotelRepository hotelRepository;
public List<Contract> getAllContracts(){
return contractRepository.findAll();
}
public List<Contract> findByHotelId(Long hotelId,Pageable pageable){
return contractRepository.findByHotelId(hotelId, pageable);
}
public ResponseEntity<?> deleteContract(Long hotelId, Long contractId)
{
return contractRepository.findByIdAndHotelId(contractId,
hotelId).map(Contract -> {
contractRepository.delete(Contract);
return ResponseEntity.ok().build();
}).orElseThrow(() -> new ResourceNotFoundException("Comment not found
with ContractId " + contractId + " and hotelId " + hotelId));
}
My contract repository
#Repository
public interface ContractRepository extends JpaRepository<Contract, Long> {
List<Contract> findByHotelId(Long hotelId, Pageable pageable);
Optional<Contract> findByIdAndHotelId(Long id, Long hotelId);
}
I got this error when running my project
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'contractController': Unsatisfied dependency expressed through field 'contractService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'contractService': Unsatisfied dependency expressed through field 'contractRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'contractRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.sunTravel.sunRest.repository.ContractRepository.findByHotelId(java.lang.Long,org.springframework.data.domain.Pageable)! No property id found for type Hotel! Traversed path: Contract.hotel.

First Solution: based on your stack trace, Spring data is looking for id variable (primary key) in your Hotel class. So please change private long hotel_id; to private long id;
Another solution (no need to change anything just add your own query):
write your own JPA query using #Query.
Example:
#Query("SELECT contract from Contract as contract where contract.hotel.hotel_id = :hotelId")
List<Contract> findByHotelId(Long hotelId, Pageable pageable);

You should rename your Primary Key from hotel_id to id then only your repository method will work.
#Entity
#Table(name="Hotel")
public class Hotel {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="hotel_id")
private long id;
#Column(name="hotel_name")
private String hotel_name;
#Column(name="hotel_location")
private String hotel_location;
#Column(name="hotel_email")
private String hotel_email;
#Column(name="hotel_telephone")
private String hotel_telephone
// getters and setters

Related

hibernate mapping and joining table error

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Associations marked as mappedBy must not define database mappings like #JoinTable or #JoinColumn: com.company.entities.Customer.address
#Entity
#Table(name="Customers")
public class Customer {
#Id
#Column(name="customer_Id")
private int customerid;
#Column(name="Customer_Name")
private String name;
#Column (name="Customer_email")
private String email;
#Column(name="Mobile_No")
private int mobilNo;
#OneToMany(cascade= CascadeType.ALL,mappedBy="customer")
#JoinTable(name="Customer",joinColumns={
#JoinColumn(name="customer_Id", referencedColumnName="customerid")
},
inverseJoinColumns={
#JoinColumn(name="address_Id",referencedColumnName="addId")
})
private Map<String,Address> address=new HashMap<>();
#Entity
public class Address {
#Id
private int addId;
private String StreetName;
private String city;
private String state;
#ManyToOne(cascade=CascadeType.ALL)
private Customer customer;
}

How to give multiple columns as primary key in entity - JPA

I have 3 entities - Course, Module, Timeline
In the timeline entity - I want to give 2 keys as primary key i.e Composite Key. How am I supposed to give that. Please tell me about the changes that are to be done in the code below:
Course:
#Id
#Column(name = "id")
Integer courseId;
#Column(name = "course_name")
String course_name;
Module:
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "module_id")
Integer module_id;
#Column(name = "module_type")
String module_type;
#Column(name = "module_name")
String module_name;
#Column(name = "duration")
Integer duration;
#OneToOne( cascade = CascadeType.ALL)
private Course course;
Timeline:
#Id
#Column(name = "timeline_id")
Integer timeline_id;
#ManyToOne( cascade=CascadeType.ALL )
private Module module;
#ManyToOne( cascade = CascadeType.ALL)
private Course course;
Now here in timeline, I want to have course_id and timeline_id as primary keys. Please help.
Thank you in advance.
Update:
I tried using Embeddable and EmbeddedId:
#Embeddable
public class TimelineId implements Serializable{
private Integer course_id;
private Integer timelineId;
getters and setters
hashcode and equals
}
Module:
#Entity
#Table (name = "timeline")
public class Timeline {
#EmbeddedId
private TimelineId timelinepk;
#ManyToOne( cascade=CascadeType.ALL )
private Module module;
#ManyToOne( cascade = CascadeType.ALL)
private Course course;
}
But this gives an error :
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: No identifier specified for entity: com.scb.axess.playbook.model.Timeline
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1762) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.5.RELEASE.jar:5.1.5.RELEASE]
There are multiple possibilities to solve your problem:
Possibility 1: Using IdClass
Defining the IdClass type
This class has to implement the Serializable interface and the equals(..) and hashCode() methods. The class holds the parts of the composite primary key.
public class TimelineId implements Serializable {
private Integer timelineId;
private Integer courseId;
// getters & setters
#Override
public int hashCode() {
// your impl of hashCode
}
#Override
public boolean equals(Object obj) {
// your impl of equals
}
}
Modify your Timeline class
Here the #IdClass annotation is added to the entity class. Further, the class holds the same fields like the IdClass type (name and type should be identical), but annotated with #Id.
#Entity
#IdClass(TimelineId.class)
public class Timeline {
#Id
#Column(name = "timeline_id")
private Integer timelineId;
#Id
#Column(name = "course_id")
private Integer courseId;
#ManyToOne
#JoinColumn(name = "module_id")
private Module module;
// getters & setters
}
Possibility 2: Using EmbeddedId
Defining the EmbeddedId type
This class also holds the parts of the composite primary key.
#Embeddable
public class TimelineId {
#Column(name = "timeline_id")
private Integer timelineId;
#Column(name = "course_id")
private Integer courseId;
// getters & setters
}
Modify your Timeline class
In this case the single parts of the composite primary key can be omitted. Only a field of the embedded key type annotated with #EmbeddedId is defined.
#Entity
public class Timeline {
#EmbeddedId
private TimelineId timelineId;
#ManyToOne
#JoinColumn(name = "module_id")
private Module module;
// getters & setters
}
In both cases the corresponding repositories should be defined like this (TimelineId has to be used for parameter type ID) (here, JpaRepository is used):
public interface TimelineRepository extends JpaRepository<Timeline, TimelineId> {}
**Possibility 3: Don't use a composite PK, but make the columns unique**
Modify your Timeline class
#Entity
#Table(uniqueConstraints = {
#UniqueConstraint(columnNames = {
"course_id", "module_id"
})
})
public class Timeline {
#Id
#Column(name = "timeline_id")
Integer timeline_id;
#ManyToOne( cascade=CascadeType.ALL)
#JoinColumn(name = "module_id)
private Module module;
#ManyToOne( cascade = CascadeType.ALL)
#JoinColumn(name = "course_id)
private Course course;
// getters & setters
}

Multiple JPA Repositories with multiple Entity Mapping conflict

I am creating a simple one to many relationship using JPA and Spring Data Rest. But i am getting this error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'designationRepository' defined in com.example.relational.BootRelations.repository.DesignationRepository defined in #EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Cannot resolve reference to bean 'jpaMappingContext' while setting bean property 'mappingContext'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is org.hibernate.AnnotationException: No identifier specified for entity: com.example.relational.BootRelations.models.Designation
That is because I have #Entity classes like Designation and Employee, the code follows like:
#Entity
public class Designation {
private String Designation;
private float Salary;
#OneToMany(targetEntity=Employee.class, mappedBy="designation", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
#JoinColumn(name="Emp_Id")
private Set<Employee> employee;
// Getter & Setter and Constructors
}
Now Employee class:
#Entity
#Table(name="Employee")
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="Emp_Id")
private int Emp_Id;
#Column(name="Emp_Name")
private String Emp_Name;
#Column(name="Emp_Email")
private String Emp_Email;
#OneToOne(targetEntity=Designation.class, mappedBy="employee", fetch=FetchType.LAZY, cascade=CascadeType.ALL)
private Designation designation;
// // Getter & Setter and Constructors
}
The repositories are:
public interface DesignationRepository extends JpaRepository<Designation, Integer> {}
public interface EmployeeRepository extends JpaRepository<Employee, Integer> {}
Services:
#Service
public class DesignationServiceImpl implements DesignationService {
private DesignationRepository designationRepository;
#Autowired
public DesignationServiceImpl(DesignationRepository designationRepository) {
this.designationRepository = designationRepository;
}
#Override
public List<Designation> findAllDesignation() {
return designationRepository.findAll();
}
}
public class EmployeeServiceImpl implements EmployeeService {
private EmployeeRepository employeeRepository;
#Autowired
public EmployeeServiceImpl(#Qualifier("employeeJPAImpl") EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
}
#Service
public class DesignationServiceImpl implements DesignationService {
private DesignationRepository designationRepository;
#Autowired
public DesignationServiceImpl(#Qualifier("DesignationRepository") DesignationRepository designationRepository) {
this.designationRepository = designationRepository;
}
#Override
public List<Designation> findAllDesignation() {
return designationRepository.findAll();
}
}
As I had two entities I had two controllers:
#RestController
#RequestMapping("/api")
public class DesignationController {
private DesignationService designationService;
#Autowired
public DesignationController(DesignationService designationService) {
this.designationService = designationService;
}
#GetMapping("/designation")
public List<Designation> getAllDesignation(){
return designationService.findAllDesignation();
}
}
and
#RestController
#RequestMapping("/api")
public class EmployeeController {
private EmployeeService employeeService;
#Autowired
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
// Mappings
}
Can anyone help me solve this issue? Until I had one entity it was working fine; as soon as I added another one it failed to start, with the error. Please help me fix the issue.
In Employee class make this changes.
#Entity
#Table
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column
private Long empId;
#Column
private String Name;
#Column
private String Email;
#OneToMany(targetEntity=Designation.class, fetch=FetchType.LAZY, cascade=CascadeType.ALL)
private Designation designation;
// // Getter & Setter and Constructors
}
In the Designation class, make this changes..
#Entity
public class Designation {
#Id
private Long id;
private String role;
private float salary;
#ManyToOne(targetEntity=Employee.class, fetch=FetchType.LAZY, cascade=CascadeType.ALL)
#JoinColumn
private Set<Employee> employee;
// Getter & Setter and Constructors
}
This will result in a table structure like this.
Employee
EMP_ID
NAME
EMAIL
Designation
ID
ROLE
SALARY
EMPLOYEE_ID
In OneToMany and ManyToOne association, we must keep a note that, which class is holding the Many side. That side is known as the owning side. As that class will contain the foreign key. Here, our designation class is containing the Many side. So, it will create a foreign key automatically.
If we give the #JoinColumn in the Employee class. Still we will get the Designation class as the Owning class.
You can refer this article, for more details.
Rather than this, let me tell you some of your major mistakes.
Do not give the variables name same as your class name.
By writing variables name as empId in java file, it will result EMP_ID in database.
If a column name or a table name is same your variable name, you can avoid re-mentioning it.
means, if my entity class name is Employee. And I want my database Table name should also be EMPLOYEE. I can avoid specifying #Table(name="EMPLOYEE").
I hope it would be helpful !!

i'm getting null value in a child table as a foreign key of parent table using spring data rest or spring data jpa accosiation

enter image description here In this image first address for empId 1 and last two records are empid 2 (empid 2 haveing to address)
file:///home/user/Pictures/fk.png
#Entity
#Table(name = "Employee")
public class Employee {
#Id
#GeneratedValue
private Integer id;
private String name;
private Integer sal;
#OneToMany(cascade = CascadeType.ALL,mappedBy="employee")
private List<Address> addresses;
//getter setter
Child entity
#Entity(name="Address")
public class Address {
#Id
#GeneratedValue
private Integer aid;
private String city;
private String state;
#ManyToOne
#JoinColumn(name="id")
private Employee employee;
//getter setter
Repository
#Repository
#RepositoryRestResource(path="employee")
public interface EmployeeRepo extends JpaRepository<Employee,Integer> {
}
Input from RestClient
{
"name":"rdhe",
"sal":"20000",
"addresses":[{
"city":"hyd",
"state":"ts"
}]
}
if i use spring data jpa then code will be
// jpa Repository
public interface EmployeeRepo extends JpaRepository<Employee,Integer> {
}
// EmployeeServer class
#Service
public class EmployeeService {
#Autowired
EmployeeRepo employeeRepo;
public void saveEmployee(Employee employee){
employeeRepo.save(employee);
}
}
// controller
#RestController
public class EmployeeController {
#Autowired
EmployeeService employeeService;
#PostMapping(path="/save")
public void saveEmp(#RequestBody Employee employee){
employeeService.saveEmployee(employee);
}
}
if i'll use spring-data-rest at that time no need to create employeeService and controller class
I was getting the same problem until JsonManagedReference came to my rescue.
Try changing your entities to include them like this:
In the Employee Entity:
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy ="employee")
#JsonManagedReference
private List<Address> addresses;
In the Address Entity:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id", nullable = false, updatable = false, insertable =true)
#JsonBackReference
private Employee employee;
I was not able to find why it works this way, so please let me know if you come to know :)
It is probably due to the fact that your mentioning #JoinColumn(name="id"). The name attribute in #JoinColumn defines the name of the foreign key field in the child table. Since you are specifying foreign key column as id on hibernate, it could be the issue. Please update it to the same name(ie fk_empid) as specified in database, it should work...

converting URI to entity with custom controller in spring data rest?

i have an jpa entity like this.
#Entity
#Table(name = "location")
#Data
public class Location {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "LOCATION_ID", unique = true)
#NotEmpty(message = "Please Enter Location ID")
private String name;
#Column(name = "LOCATION_DESCRIPTION")
#NotEmpty(message = "Please Enter Location Description")
private String description;
#ManyToOne
#NotNull(message = "Please Choose a Building")
Building building;
#Version
Long version;
}
and the repository like this.
public interface LocationRepository extends PagingAndSortingRepository<Location, Long> {
Location findByName(#Param("name") String name);
}
i am using spring data rest i am able to create location with rest api by providing the following payload
{
"name":"adminxxxxx","description":"adminxxx" , "building": "http://localhost:8080/buildings/2"
}
now i am trying to write my custom controller which will persist the entity. this is my custom controller
#ExposesResourceFor(Location.class)
#RepositoryRestController
#BasePathAwareController
public class LocationController {
#Autowired
LocationRepository locationDao;
#Autowired
LocationResourceAssembler resourceAssembler;
#Value("${buildings.error.messages.uniqueconstraintviolation}")
String uniqueConstrainMessage;
static final String TAG = LocationController.class.getSimpleName();
#RequestMapping(value="locations",method = org.springframework.web.bind.annotation.RequestMethod.POST)
public ResponseEntity<?> save(#RequestBody #Valid Location location) {
try {
location = locationDao.save(location);
LocationResource b = resourceAssembler.toResource(location);
return ResponseEntity.ok().body(b);
} catch (DataIntegrityViolationException e) {
if (locationAlreadyExists(location.getName()))
throw new LocationAlreadyExistException(uniqueConstrainMessage, location);
else
throw new RuntimeException("Some Error Occured");
}
}
i am getting this error
exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.alamdar.model.Building: no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/buildings/2')
at [Source: java.io.PushbackInputStream#5d468b16; line: 3, column: 60] (through reference chain: com.alamdar.model.Location["building"])</div></body></html>
can anyone please help?
I am not sure why you are writing a custom controller however the issue would appear to be that you do not have a default no args constructor so Jackson cannot instantiate an instance.
This is because you are using Lombok's #Data annotation:
https://projectlombok.org/features/Data.html
You should also annotate you class with #NoArgsConstructor to have a default no-args constructor generated:
#Entity
#Table(name = "location")
#Data
#NoArgsConstructor
public class Location {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "LOCATION_ID", unique = true)
#NotEmpty(message = "Please Enter Location ID")
private String name;
#Column(name = "LOCATION_DESCRIPTION")
#NotEmpty(message = "Please Enter Location Description")
private String description;
#ManyToOne
#NotNull(message = "Please Choose a Building")
Building building;
#Version
Long version;
}

Resources