Given this hypothetical table structure:
person
id | reference | name
book
id | name | person_id
And this class structure
#Entity(name = "book")
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "id")
Long id;
#Column(name = "name")
String name;
// WHAT GOES HERE?
UUID personReference;
...
}
#Repository
public interface BookRepository extends JpaRepository<Book, Long> {
}
How would one insert the book row while using a select the person.id using the personReference field on the Book class. A query that would usually look like this:
insert into book (name, person_id)
values (?, (select id from person p where p.reference = ?))
Is this something that is possible through annotations or should I look to just implement a query?
Hibernate is an implementation of the Java Persistence API (JPA) which is a Java specific Object Relational Model (ORM). The purpose of ORMs is to handle sql rows as objects & it includes relations as well.
#Entity
public class Book implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
Long id;
String name;
// relational mapping
#ManyToOne // an author can write multiple books. but a book has a single author
Person author; // an author is a Person not an UUID
}
But to store Person object in your db, you need to have a Person Entity as well.
#Entity
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
long id; // primitive types can be primary keys too
String name;
}
I strongly advise to learn the basics of JPA (Specification)
Then, in your #Repository classes (Spring specific):
#Repository
public BookRepository implements CrudRepository<Book,Long> {
}
#Repository
public PersonRepository implements CrudRepository<Book,Long> {
}
Finally, in your #Service class (Spring specific):
#Service
public class BookService {
PersonRepository personRepo;
BookRepository bookRepo;
public BookService(PersonRepository personRepo, BookRepository bookRepo) {
this.personRepo = personRepo;
this.bookRepo = bookRepo;
}
public void setBookAuthor(Book book, Person author) {
book.setAuthor(author);
bookRepo.save(book);
}
public void setBookAuthor(long bookId, long personId) {
Book book = bookRepo.findById(bookId);
Person author = userRepo.findById(personId);
setBookAuthor(book, author);
}
}
If Person is not mapped as an entity, you can use native SQL queries.
I'm not sure if this is an error, but the mapping should be:
#Column(name="person_id")
UUID personReference;
If that's a valid native SQL query, you can do the insert using it:
#Modifying
#Query(nativeQuery=true, value="insert into book (name, person_id) values (?1, (select id from person p where p.reference = ?2))")
public int insert(String name, String reference);
Your question doesn't contain enough info to figure out if you can map Person as an entity. If that's the case, this article might help you.
I have a two table Company and CompanyRepo like below
COMAPNY
COMPANY_REPO
I have entities for those two tables like this :
#Entity
#Table(name="COMAPNY")
public class Company implements Serializable {
#Id
#Column(name="COMPANY_ID")
private Long companyId;
#Column
private String companyName;
#OneToMany(mappedBy="COMPANY")
private List<CompanyRepo> companyRepo;
}
#Entity
#Table(name="COMAPNY_REPO")
public class CompanyRepo implements Serializable {
#Id
#Column(name="COMPANY_REPO_ID")
private Long companyRepoId;
#Column
private String COMPANY_ID;
#Column
private String DEPT_ID;
#ManyToOne
#JoinColumn(name="COMPANY_ID")
private Company company;
}
Now i want to execute below query using a Hibernate relationship mapping
select Company_name from company as C ,company_repo as cr where c.company_id=cr.company_id and dept_id=10
I wrote a JPA repository like below by using a #OneToMany in Company table and #ManyToOne in CompanyRepo. But in resultant I am getting multiple COMPANYobject inside COMPANY_REPO Object.Does my relationship mapping is correct ?
public interface CompanyRepository extends JpaRepository<CompanyRepo, Long> {
public CompanyRepo findByDeptId(Long deptId);
}
Given your current database design, try something such as the following:
public interface CompanyRepository extends JpaRepository<Company, Long> {
#Query(value="SELECT * from company as C WHERE c.company_id = (SELECT cr.company_id FROM company_repo as cr WHERE cr.dept_id = ?1)", nativeQuery=true)
public Company findByDeptId(Long deptId);
}
The #Query annotation is a very powerful and flexible way to define methods in Repository interface. If you need more complex logic, I would recommend reading about the use and possibilities of the annotation. See here.
Based on your entity class your have multiple
COMPANY_ID that is not a proper way to declare your column name.
#Column
private String COMPANY_ID;
#ManyToOne
#JoinColumn(name="COMPANY_ID")
private Company company;
So please change your #Column
private String COMPANY_ID; to #Column("comp_id)
private String companyId;
If you want to get the CompanyRepo based on Company type then you need to change your query to fetch the dept id.
And your #Column
private String DEPT_ID; is String datatype so pass String to your repository.
#Query(" select companyRepo.company from CompanyRepo as companyRepo where companyRepo.DEPT_ID = :deptId")
public Company findByDeptId(String deptId);
I am mapping three entities. Doctor, Client (which extends a Person) and MedicalConsultation.
See my code above. Consider all models class with a default constructor, a constructor with all fields and the getters and setters:
#Entity
#Table (name= "person")
public abstract class Person {
#Id #GeneratedValue
protected Long id;
protected String name;
protected String email;
protected String password;
#OneToOne
protected Address address;
Now the class Doctor.
#Entity(name = "doctor")
public class Doctor extends Person{
#OneToMany(mappedBy="doctor" , fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JsonManagedReference(value = "job-historical")
private List<MedicalConsultation> medicalConsultations;
#Enumerated
private Type type;
#ElementCollection
private List<String> specialties;
public Doctor() {
super();
}
public Doctor(String name, String email, String password, Address address,
List<String> specialties, Type type,
List<MedicalConsultation> medicalConsultations) {
super(name,email,password,address);
this.setMedicalConsultations(medicalConsultations);
this.setSpecialties(specialties);
this.setType(type);
}
My constructors calls the super() and sets their values acording to the super class and its own properties. The same happens with the Client class.
#Entity(name = "client")
public class Client extends Person{
#JsonManagedReference(value = "client-consultations-historical")
#OneToMany(mappedBy="doctor" , fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<MedicalConsultation> medicalConsultations;
Here, the Medical Consultation model, which get the other two models
#Entity
#Table(name = "medical_consultation")
public class MedicalConsultation {
#Id
#GeneratedValue
private Long id;
#JsonBackReference(value = "job-historical")
#ManyToOne
#JoinColumn(name="doctor_fk")
private Doctor doctor;
#ManyToOne
#JoinColumn(name="client_fk")
#JsonBackReference( value = "client-consultations-historical")
private Client client;
#JsonFormat(pattern = "dd/MM/yyyy hh:mm")
private Date date;
private BigDecimal price;
Finally, we got the problem:
On my controller class, I cannot get the full data of medicalConsultations. That is, I got the data, the ID and the price, but I do not get the Client and the Doctor for some reason.
But, if I call the method getDoctor() or getClient and return one of them, I do see all the information.
See the method on the RestControl Class:
#RestController
public class Control {
#Autowired
private PersonRepository personRepo;
#Autowired
private ClientRepository clientRepo;
#Autowired
private AddressRepository addressRepo;
#Autowired
private DoctorRepository doctorRepo;
#Autowired
private MedicalConsultationRepository consultationRepo;
#GetMapping("consultations")
public List<MedicalConsultation> getConsultations() {
List<MedicalConsultation> consultations = this.consultationRepo.findAll();
return consultations;
}
Maybe there is something wrong on the Mapping. But I set the hibernate to show the sql, and it apparently makes all the query getting everything that I want. See:
Hibernate:
select
medicalcon0_.id as id1_2_,
medicalcon0_.client_fk as client_f4_2_,
medicalcon0_.date as date2_2_,
medicalcon0_.doctor_fk as doctor_f5_2_,
medicalcon0_.price as price3_2_
from
medical_consultation medicalcon0_
Hibernate:
select
client0_.id as id2_3_0_,
client0_.address_id as address_7_3_0_,
client0_.email as email3_3_0_,
client0_.name as name4_3_0_,
client0_.password as password5_3_0_,
address1_.id as id1_0_1_,
address1_.city as city2_0_1_,
address1_.number as number3_0_1_,
address1_.phone as phone4_0_1_,
address1_.street as street5_0_1_,
medicalcon2_.doctor_fk as doctor_f5_2_2_,
medicalcon2_.id as id1_2_2_,
medicalcon2_.id as id1_2_3_,
medicalcon2_.client_fk as client_f4_2_3_,
medicalcon2_.date as date2_2_3_,
medicalcon2_.doctor_fk as doctor_f5_2_3_,
medicalcon2_.price as price3_2_3_,
client3_.id as id2_3_4_,
client3_.address_id as address_7_3_4_,
client3_.email as email3_3_4_,
client3_.name as name4_3_4_,
client3_.password as password5_3_4_
from
person client0_
left outer join
address address1_
on client0_.address_id=address1_.id
left outer join
medical_consultation medicalcon2_
on client0_.id=medicalcon2_.doctor_fk
left outer join
person client3_
on medicalcon2_.client_fk=client3_.id
where
client0_.id=?
and client0_.dtype='client'
Hibernate:
select
doctor0_.id as id2_3_0_,
doctor0_.address_id as address_7_3_0_,
doctor0_.email as email3_3_0_,
doctor0_.name as name4_3_0_,
doctor0_.password as password5_3_0_,
doctor0_.type as type6_3_0_,
address1_.id as id1_0_1_,
address1_.city as city2_0_1_,
address1_.number as number3_0_1_,
address1_.phone as phone4_0_1_,
address1_.street as street5_0_1_,
medicalcon2_.doctor_fk as doctor_f5_2_2_,
medicalcon2_.id as id1_2_2_,
medicalcon2_.id as id1_2_3_,
medicalcon2_.client_fk as client_f4_2_3_,
medicalcon2_.date as date2_2_3_,
medicalcon2_.doctor_fk as doctor_f5_2_3_,
medicalcon2_.price as price3_2_3_,
client3_.id as id2_3_4_,
client3_.address_id as address_7_3_4_,
client3_.email as email3_3_4_,
client3_.name as name4_3_4_,
client3_.password as password5_3_4_
from
person doctor0_
left outer join
address address1_
on doctor0_.address_id=address1_.id
left outer join
medical_consultation medicalcon2_
on doctor0_.id=medicalcon2_.doctor_fk
left outer join
person client3_
on medicalcon2_.client_fk=client3_.id
where
doctor0_.id=?
and doctor0_.dtype='doctor'
Can Someone tell me what is happing?
try you mapping annotation like bellow on MedicalConsultation.
#ManyToOne(fetch = FetchType.EAGER)
private Doctor doctor;
I have the following entities: ShoppingCart, abstract class User and EndUser that extends User. AddressDetails is an embedable that is embeded into EndUser entity.
My query looks like this: SELECT sc FROM ShoppingCart sc JOIN sc.endUser as endUser WHERE endUser.name EQ someName and endUser.addressDetails.zip EQ 1234
When I remove the second part of the WHERE clause, and leave just the endUser.name part, everything works fine (name is a property of endUser entity class which is a subclass of User entity class).
However, when I try the whole query I get:
org.hibernate.QueryException: could not resolve property: zip of:
ShoppingCart:
#Entity
public class ShoppingCart {
...
#ManyToOne(fetch = FetchType.LAZY)
#JoinTable
private EndUser endUser;
}
User:
#Entity
public abstract class User {
...
}
EndUser:
#Entity
public class EndUser extends User {
...
#Column
private String name;
#Embeded
private AddressDetails addressDetails;
...
}
Address Details:
#Embeddable
public class AddressDetails {
...
private int zip;
...
}
I actually found the problem.
When I change FetchType to EAGER on #ManyToOne reladtionship between ShoppingCart and endUser the query works.
So it should be:
#ManyToOne(fetch = FetchType.EAGER)
#JoinTable
private EndUser endUser;
I am using Sprind JPA, Spring 3.1.2(in future 3.2.3), Hibernate 4.1 final.
I am new to Sprind Data JPA. I have tow Table Release_date_type and Cache_media which entities are as follows :
ReleaseAirDate.java
#Entity
#Table(name = "Release_date_type")
public class ReleaseDateType {
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
private Integer release_date_type_id;
#Column
private Integer sort_order;
#Column
private String description;
#Column
private String data_source_type;
#Column(nullable = true)
private Integer media_Id;
#Column
private String source_system; with getters and setters..
and CacheMedia as
#Entity
#Table(name = "Cache_Media")
public class CacheMedia {
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
private Integer id;
#Column(name="code")
private String code;
#Column(name="POSITION")
private Integer position;
#Column(name="DESCRIPTION")
private String media_Description; with setter and getters.
Now my repository interface is as follows :
public interface ReleaseDateTypeRepository extends CrudRepository<ReleaseDateType, Long>{ }
Now i want to write a method(Query) in ReleaseDateTypeRepository interface which can get all the data from Release_Date_Type table including appropriate media_description from Table 'Cache_Media' based on media_id of Release_date_type table.
So my select (SQL)query looks like
SELECT * from Release_Date_Type r left join Cache_Media c on r.media_id=c.id
I don't know how to map entities.
I tried so many thing but not luck.
Any help is appreciated.
Its not the answer for joining via Hibernate, but alternatively you can create a view with your join and map the view to your objects