I have
#Entity
public class Person{
...
#OneToMany
#JoinColumn(name = "person_id")
private List<Email> emailList = new ArrayList<>();
...
}
#Entity
public class Email{
...
private String emailAddress;
...
}
I need to get Person by emailAddress. I saw this answer: dont like.
But i wonder - can i do this with only spring data, i mean - without query.
This should work:
Person findPersonByEmailList_EmailAddress(String email);
And this as well:
#Query("select p from Person p join p.emailList l where l.emailAddress = ?1")
Person getPersonByEmail(String email);
Related
I'm looking for a way to make a join on a one-to-many relation where the many-side is defined through inheritance and the right part of the join is restricted to a specific subclass (downcast).
Say I have the entities below (example taken from here):
#Entity
public class Project {
#Id
#GeneratedValue
private long id;
private String name;
#OneToMany(cascade = CascadeType.ALL)
private List<Employee> employees;
.............
}
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Entity
#DiscriminatorColumn(name = "EMP_TYPE")
public class Employee {
#Id
#GeneratedValue
private long id;
private String name;
.............
}
#Entity
#DiscriminatorValue("F")
public class FullTimeEmployee extends Employee {
private int annualSalary;
.............
}
#Entity
#DiscriminatorValue("P")
public class PartTimeEmployee extends Employee {
private int weeklySalary;
.............
}
#Entity
#DiscriminatorValue("C")
public class ContractEmployee extends Employee {
private int hourlyRate;
.............
}
I can easily build join queries that involve properties defined in the superclass Employee, like:
JPAQuery query = ...
QProject project = new QProject("p");
QEmployee employee = new QEmployee("e");
query.join(project.employees, employee);
query.where(employee.name.startsWith("A"));
But if I want to access a property of subclass, say FullTimeEmployee.annualSalary, and hence restrict the join to that sub-type, how do I do that?
How do I build the the equivalent of following JPQL:
SELECT DISTINCT p FROM Project p JOIN TREAT(p.employees AS FullTimeEmployee) e WHERE e.annualSalary > 100000
You can do it like this:
EntityManager em = ...;
QProject p = QProject.project;
QFullTimeEmployee e = QFullTimeEmployee.fullTimeEmployee;
List<FullTimeEmployee> emps = new JPAQuery<>(em)
.select(p)
.distinct()
.from(p)
.innerJoin(p.employees, e._super)
.where(e.annualSalary.gt(100000))
.fetch();
See also this post on the Querydsl forum: https://groups.google.com/d/msg/querydsl/4G_ea_mQJgY/JKD5lRamAQAJ
I'm using Spring boot 1.5 and Hibernate. I have 2 entities, Person and PersonDetail which doesn't always exist. I need to retrieve a list of PersonDetails based on a Person list, even if matched PersonDetails doesn't exists.
So I wrote buildFromPersonList in PersonService which is working well. However I have filled my DB with 1000 entries of Person and unfortunately it takes about 3,5 seconds to build the list of PersonDetails.
Due to performances issues i'm trying to do it in JPQL please take a look at findAllByPersons and help me to improve it to get PersonDetails from PersonList and retrieve matching PersonDetails when it exists .
Here's my entities
#Entity
#Table(name = "person")
public class Person{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
protected Long id;
//name,birthdate ...
}
#Entity
#Table(name = "person_details")
public class PersonDetails{
// private details accessible only for authorized user
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
protected Long id;
#OneToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "id_person",insertable = true,updatable=true,nullable = false)
protected Person person;
}
Repository
#Transactional
public interface PersonDetailsRepository extends JpaRepository<PersonDetails,Long> {
PersonDetails findByPerson(Person person);
// #Query("SELECT CASE WHEN (pd is not null ) THEN pd ELSE (new PersonDetails(p)) END FROM Person p left join PersonDetails pd on p.id=pd.person.id")
#Query("SELECT new PersonDetails(p) FROM Person p")
List<PersonDetails> findAllByPersons();
}
Service
#Service
public class PersonDetailsService {
private final PersonDetailsRepository personDetailsRepository;
private final PersonService personService;
// constructors + findall, findOne,save
#Override
public List<PersonDetails> findAll() {
List<Person> personList=personService.findAll();
return buildFromList(personList);
// return personDetailsRepository.findAllByPerson();
}
private List<PersonDetails> buildFromPersonList( List<Person> personList) {
List<PersonDetails> personDetailsList= new ArrayList<>();
for (Person person:personList) {
PersonDetails personDetails = personDetailsRepository.findByPersonperson);
if(personDetails==null){
personDetails=new PersonDetails();
personDetails.setPerson(person);
}
personDetailsList.add(personDetail);
}
return personDetailsList;
}
}
Update : I've implemented a new solution based on TheBakker idea but it still take too much time to load (between 800ms and 1s for only 1000 entries).
Does anyone have an idea to retrieve faster ?
Here's my new code :
#Transactional
public interface PersonDetailsRepository extends JpaRepository<PersonDetails,Long> {
//..
#Query("SELECT new PersonDetails(p) FROM Person p WHERE p.id not in (SELECT pd.person.id From PersonDetails pd)")
List<PersonDetails> findAllPersonNotInPersonDetails();
}
#Service
public class PersonDetailsService {
#Override
public List<PersonDetails> findAll() {
List<PersonDetails> personDetailsList=personDetailsRepository.findAll();
/* personDetailsList.addAll(personDetailsRepository.findAllPersonsNotInPersonDetails());
return personDetailsList;*/
return Stream.concat(personDetailsList.stream(), agentDetailsRepository.findAllPersonNotInPersonDetails().stream())
.collect(Collectors.toList())
}
}
As it is, you are doing 1000 select queryies in your DB to get the personDetail for each individual Person.
Something that would be faster (but still perfectible) would be to do 2 queries :
One that get all the PersonDetails already in your DB
Another that would get all the person from your list that do not have a PersonDetails and for which you will need to loop on and instantiate one.
That way you change 1000 queries / transactions in 2, and you should definitly gain some.
I have a One-to-Many relation:
public class Account{
#OneToMany(cascade=CascadeType.ALL)
private List<Transaction>transactions = new ArrayList<>();
}
public class Transaction{
#ManyToOne
#JoinColumn(name="ACCOUNT_ID")
private Account account;
}
I want to get all Accounts for a User, and it works, but Transaction list is empty. Is this a matter of entity mapping or should I modify my query?
I started with (empty transaction list):
TypedQuery<Account>query = em.createQuery("SELECT a FROM Account a WHERE a.user.id = ?1",Account.class);
also tried to join like so (no accounts returned at all):
TypedQuery<Account>query = em.createQuery("SELECT a FROM Account a JOIN a.transactions t WHERE a.user.id = ?1",Account.class);
What's wrong here?
It seems you forgot to add mappedBy in the annotation properties:
#OneToMany(cascade=CascadeType.ALL, mappedBy="account")
private List<Transaction>transactions = new ArrayList<>();
I have a function that merges two tables, each of these tables has a column that I want to filter.
#Entity
public class Contacts {
#Id
private int id;
#ManyToOne //reference user_id = id
private User user;
#ManyToOne //reference people_id = id
private People people;
//getters and setters
}
#Entity
public class User {
private int id;
private int name;
private Enterprise enterprise;
//getters and setters
}
#Entity
public class People {
private int id;
private int name;
//..others fields
private Enterprise enterprise;
//getters and setters
}
I need to list all "Contacts" where my enterprise id = 1. On a simple select (SQLServer), it will be:
SELECT c.* FROM CONTACTS c
INNER JOIN User u ON u.id = c.user_id
INNER JOIN People p on p.id = p.people_id
WHERE u.empresa_id = 1
I can't figure out how to do it with Criteria API, I already tried the follow code, but I keep receiving an error.
//code..public List<Obj> list(int id) {
Criteria crit = session.createCriteria(Contacts.class);
crit.add(Restrictions.eq(user.enterprise.id, id)); //it doesn't work!
crit.list();
}
org.hibernate.QueryException: could not resolve property: user.enterprise.id of: sys.com.model.Contacts
here i am writing code for sample using criteria.
public List<Student_document> getUserById(int id) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(
Student_document.class);
criteria.add(Restrictions.eq("user_document.user_Id", id));
return criteria.list();
}
In hibernate, when I use the joined strategy. does hibernate support polymorphism?
for example:
#Entity
#Table(name = "PERSON")
#Inheritance(strategy=InheritanceType.JOINED)
public class Person {
#Id
#GeneratedValue
#Column(name = "PERSON_ID")
private Long personId;
#Column(name = "FIRSTNAME")
private String Fullname;
public Person() {
}
public Person(String fullname) {
this.Fullname= fullname
}
}
and the derived class:
#Entity
#Table(name="EMPLOYEE")
#PrimaryKeyJoinColumn(name="PERSON_ID")
public class Employee extends Person {
#Column(name="department_name")
private String departmentName;
public Employee() {
}
public Employee(String fullname, String departmentName,) {
super(fullname);
this.departmentName = departmentName;
}
}
also all the fields include the getter and setters.
so in my main, when I'll do this:
session.beginTransaction();
person e = new Employee();
e.setFullname("james");
e.setdepartmentName("R&D");
session.getTransaction().commit();
I know for a fact that if e was of Employee type, hibernate would have created a row for both Employee and Person tables.
but for this example will hibernate generate queries for person and employee?
in other words, will hibernate support the polymorphic behavior?
When I understand you question correctly than you want to know if hibernate does in that case automtically return Employees when you query for all Persons. Additionally if it inserts an Employee when the object is declared as Person p = new Employee().
Short answer to both yes. More detailed.
The insert operation is based on the actual type of the object and not on exactly the type written in your sourcecode.
Related to querying of Persons. Hibernate does left outer join all subtypes so you will get also Employess back when you do the following:
Query query = session.createQuery("From Person ");
List<Person> persons = query.getResultList();