I have 3 tables (Entities) (postgreSQL):
#Entity
#Table(name = "application", schema = "applications")
public class Application implements Serializable {
#Id
#GeneratedValue
#Column(name = "application_id")
private long applicationId;
#Column(length = 400)
#Size(min=50, max=400)
private String applicationDescribing;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "customerId")
private Customer Customer;
.....
Also I have the abstract class User with child class Customer, which has its own table in DB.
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private Long userId;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "localitiesId")
private Localities userLocality;
.....
#Entity
#AttributeOverride(name="userId", column=#Column(name="customerId"))
public class Customer extends User {
#Column(length = 8)
private String userType;
.....
User and also Customer table has many to one related table Locality, connected via id.
#Entity
#Table(name = "localities", schema = "resource")
public class Localities implements Serializable {
#Id
#GeneratedValue
#Column(name = "id")
private long localitiesId;
#Column(name = "region", length = 50)
private String region;
....
I try to realize seaching via Application, using (String) keyWord and locality_id (long) locality.
First approach:
#Query(value = "SELECT u FROM Application u WHERE u.applicationDescribing LIKE %:keyWord% " +
"AND userLocality IN (SELECT c FROM User c WHERE c.userLocality IN " +
"(SELECT l FROM Localities l WHERE l.localitiesId = :locality))")
List<Application> getApplicationsByKeyWordsAndRegion(#Param("keyWord") String keyWord, #Param("locality") long locality);
Second approach (recomended by richyen):
#Query(value = "SELECT a FROM Application a " +
"JOIN Customer c ON a.customerid = c.userid " +
"JOIN Localities L ON c.localitiesid = L.id " +
"WHERE a.applicationDescribing LIKE %:keyWord% AND L.id = :locality")
List<Application> getApplicationsByKeyWordsAndRegion(#Param("keyWord") String keyWord, #Param("locality") long locality);
Both dont work. As a result I need List <Application>, which have "keyWord" in describing field and locality in Application.Customer.locality_id. Please help
Is this what you're looking for?
SELECT a.*
FROM application a
JOIN (SELECT * FROM customer c UNION ALL SELECT * FROM executor e) as u on a.customer_id=u.id
JOIN locality l on u.locality_id=l.id
WHERE a.description like '%<keyWord>%'
AND l.region = <region>;
I guess one question I have for you is: how do you differentiation between Customer ID and Executor ID?
Correct answer:
SELECT app FROM Application app
INNER JOIN app.Customer customer
INNER JOIN customer.userLocality
locality WHERE customer.userLocality.id
= :locality AND app.applicationDescribing
LIKE CONCAT('%',:keyWord,'%')
Related
I have a User entity (table user_entity), which is linked with role (table keycloak_role) through reference table user_role_mapping. User can have multiple roles. I need to recieve a user with client_role = false. Since my reference table is named differently than hibernate expects, I've used #JoinTable to let it know correct ref table name. But when I run it, I recieve a User with all roles. I've added #WhereJoinTable to roles list, but Hibernate builds an incorrect query and tries to access client_role column in ref table user_role_mapping. How can I fix it?
User class
#Entity
#Table(name = "user_entity")
#Getter
#Setter
#EqualsAndHashCode
public class UserEntity {
#Id
#Column(name = "id")
private String id;
private String email;
#Column(name = "email_constraint")
private String emailConstraint;
#Column(name = "email_verified")
private String emailVerified;
private boolean enabled;
#Column(name = "federation_link")
private String federationLink;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
private String username;
#Column(name = "created_timestamp")
private Long createdAt;
#OneToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "user_group_membership",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "group_id")
)
private List<Group> groups;
#OneToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "user_role_mapping",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "role_id", referencedColumnName = "id")
)
#WhereJoinTable(clause = "client_role = false")
private List<Role> realmRoles;
}
Role class
#Entity(name = "keycloak_role")
#Table(name = "keycloak_role")
#Getter
#Setter
public class Role {
#Id
private String id;
private String name;
}
Hibernate query from logs. Last WHERE is what is wrong
Hibernate:
select
*
from
user_entity ue
join
user_group_membership ugm
on ugm.user_id = ue.id
join
keycloak_group kg
on kg.id = ugm.group_id
join
realm r
on r.id = ue.realm_id
where
username = ?
and r.id = 'CSP'
and kg.name in (
?, ?
)
Hibernate:
select
userattrib0_.id as id1_2_,
userattrib0_.name as name2_2_,
userattrib0_.user_id as user_id4_2_,
userattrib0_.value as value3_2_
from
user_attribute userattrib0_
left outer join
user_entity userentity1_
on userattrib0_.user_id=userentity1_.id
where
userentity1_.id=?
Hibernate:
select
groups0_.user_id as user_id1_4_0_,
groups0_.group_id as group_id2_4_0_,
group1_.id as id1_0_1_,
group1_.name as name2_0_1_
from
user_group_membership groups0_
inner join
keycloak_group group1_
on groups0_.group_id=group1_.id
where
groups0_.user_id=?
Hibernate:
select
realmroles0_.user_id as user_id1_5_0_,
realmroles0_.role_id as role_id2_5_0_,
role1_.id as id1_1_1_,
role1_.name as name2_1_1_
from
user_role_mapping realmroles0_
inner join
keycloak_role role1_
on realmroles0_.role_id=role1_.id
where
(
realmroles0_.client_role = false
)
and realmroles0_.user_id=?
If what I'm trying to do is impossible yet, I guess I'll have to use native query in my repo. But it does not work as intended and still returns all roles. Yet, if I run this exact query through the console, it returns 3 records with exact roles I need.
Repository
#Repository
public interface UserRepository extends JpaEntryRepository<UserEntity> {
#Query(value = "select * from user_entity ue " +
"join user_group_membership ugm on ugm.user_id = ue.id " +
"join keycloak_group kg on kg.id = ugm.group_id " +
"join realm r on r.id = ue.realm_id " +
"join user_role_mapping urm on ue.id = urm.user_id " +
"join keycloak_role kr on urm.role_id = kr.id " +
"where username = :username " +
"and r.id = 'REALM' " +
"and kr.client_role = false " +
"and kg.name in :groups ",
nativeQuery = true)
Optional<UserEntity> findByUsernameAndGroups(#Param("username") String username,
#Param("groups") List<String> groups);
}
Using #Where instead of #WhereJoinTable in User class solves the problem
I am stuck in a tricky situation while writing a JPQL query, following are my tables:-
Order_
order_id quotation_id
1 11
2 12
Quotation
q_id qr_id
11 101
12 102
QRequest
qr_id name
101 Name 1
102 Name 2
#Entity
#Table(name = "Order_")
public class Order {
#Id
#GeneratedValue
private long id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "q_id", unique = true)
private Quotation quotation;
}
#Entity
public class QRequest {
#Id
#GeneratedValue
private long id;
#Column(nullable = false)
private String name;
}
#Entity
public class Quotation {
#Id
#GeneratedValue
private long id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "qr_id", nullable = false)
private QRequest qRequest;
}
public List<QRequest> getQRequestForOrders(List<Long> orderIds) {
String query = "Select qr from QRequest qr, Quotation q, Order o " +
"where o.quotation.qRequest.id = qr.id " +
"and o.id in (:orderIds) ";
TypedQuery<QRequest> typedQuery = entityManager.createQuery(query, QRequest.class);
typedQuery.setParameter("orderIds", orderIds);
return typedQuery.getResultList();
}
I am trying to get a List<QRequest> from a List of order_id.
This is the SQL equivalent query:-
select qr.* from QRequest qr
inner join Quotation q on q.qr_id = qr.id
inner join Order_ o on o.quotation_id = q.id
where o.id in (1,2);
I am looking for a equivalent JPQL query.
In this case it may be worth to set a bi-directional relationship to make it easier to query, like this for example:
#Entity
public class QRequest {
#Id
#GeneratedValue
private long id;
#Column(nullable = false)
private String name;
#OneToMany(mappedBy = "qRequest")
private Quotation quotation;
}
#Entity
public class Quotation {
#Id
#GeneratedValue
private long id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "qr_id", nullable = false)
private QRequest qRequest;
}
"Select qr from QRequest qr " +
"join qr.quotation q "
if you want to avoid it you can instead
"Select qr from QRequest qr, Quotation q, Order o " +
"where o.quotation.qRequest.id = qr.id " +
"and o.quotation.id = q.id " +
"and o.id in (:ids) "
and .setParameter("ids", your_list);
In both cases the query will return a collection of QRequest
I have a four tables which I need to join. These four tables are:
product
service
service_type
service_duration
A product has a service, and a service has a type and duration.
The user chooses the product, the type, the service, and the duration of the service.
In the case that a service is not available for the chosen type and duration I would like to be able to get the service which has a type of lower priority (priority is attribute in the service_type table).
In php(Laravel) I am able to join like so:
DB::table('product')
->join('product_service', 'product_service.product_id', '=', 'product.id')
->join('service', 'service.id', '=', 'product_service.service_id')
->join('service_type', 'service.type_id', '=', 'service_type.id')
->join('service_duration', 'service.duration_id', '=', 'service_duration.id')
->where('product.id', id)
->where('service_type.priority', '<', priority)
->where('service_duration.duration', duration)
->where('maintenance.active', 1)
->orderBy('service_type.priority', 'desc')
->select('service.*')
->first();
How is it possible to do this with Hibernate Entity Criteria ? I want to start of by joining from the product side but in the end select the service.
I have my relations defined like so:
Product class
#Entity
#Table(name = "product")
public class product implements Serializable {
#OneToMany(fetch = FetchType.LAZY, mappedBy = "id.product", cascade=CascadeType.ALL)
private Set<ProductService> services = new HashSet<ProductService>();
}
ProductService Class:
#Entity
#Table(name = "product_service")
#AssociationOverrides({ #AssociationOverride(name = "id.service", joinColumns = #JoinColumn(name = "service_id")),
#AssociationOverride(name = "id.product", joinColumns = #JoinColumn(name = "product_id"))})
public class ProductService implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private ProductServicePK id = new ProductServicePK();
#Column(name = "price")
private Float price;
#Column(name = "code")
private String code;
}
ProductServicePK Class:
#Embeddable
public class ProductServicePK implements Serializable {
private static final long serialVersionUID = 1L;
#ManyToOne
private Product product;
#ManyToOne
private Service service;
}
Service class:
#Entity
#Table(name = "service")
public class Service implements Serializable {
#Id
#Column(name = "id")
private Long id;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "type_id")
private ServiceType type;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "duration_id")
private ServiceDuration duration;
}
So the object that 'holds' reference to the other is the product object. So I am not sure how to get the service for that product which has a priority lower than the one selected.
I want to do this with criteria or HQL.
Your Hibernate Detached Criteria will like:
DetachedCriteria criteria = DetachedCriteria.forClass(Product.class, "product")
.criteria.createAlias("product.product_service", "productService")
.createAlias("productService.service","service")
.createAlias("service.service_type","serviceType")
.createAlias("service_duration","serviceDuration")
.add(Restrictions.eq("product.id", id))
.add(Restrictions.gt("serviceType.priority", priority))
.add(Restrictions.eq("serviceDuration.duration", duration))
.setProjection(add your productService projection here)
getExecutableCriteria(session).SetMaxResults(1) ;
But i am not getting your point, why you are using from query on product instead of product_service?, because you need product_service details.
you can you use querycriteria.html, here is the doc of it->https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querycriteria.html
or you can use hql ->https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html for achieve your result.
Apparently the JPA Criteria API does not support what I need when using the composite PK pattern. I found this mentioned somewhere here. So I found the best solution was using HQL:
Query q = session.createQuery("select s "
+ "from Service s "
+ "join s.productService as ps "
+ "join s.type as t "
+ "where s.duration = :durationId "
+ "and ps.id.product.id = :productId "
+ "and t.priority <= :priorityValue "
+ "order by t.priority desc");
q.setLong("durationId", durationId);
q.setInteger("priorityValue", priorityValue);
q.setLong("productId", productId);
return (Service) q.setMaxResults(1).uniqueResult();
I am new to Hibernate and really need help from you guys....
I have following class: UserActionPerUserResult
#Entity
#Table(name = "user_action_per_user_result")
public class UserActionPerUserResult {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "user_email", nullable = false)
private String userEmail;
#ManyToOne
#JoinColumn(name = "user_action_id", nullable = false)
private UserAction userAction;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name="user_action_per_user_result_email_message",
joinColumns={#JoinColumn(name="user_action_per_user_result_id", referencedColumnName="id")},
inverseJoinColumns={#JoinColumn(name="email_message_id", referencedColumnName="id")})
#JsonIgnore
private List<EmailMessage> emailMessages;
....getters/setter....
}
In MYSQL, the UserActionPerUserResult is one table and for email Messages, there is another table called as UserActionPerUserResultEmailMessage which has email messages associate with id of the table UserActionPerUserResult.
I have all the data stored in the MySQL table, however I am not able to query it. I need to write a query to fetch the list of emailMessages. I am trying the following, but it is throwing exception.
TypedQuery<UserActionPerUserResult> messagesQuery = entityManager.createQuery(
"SELECT e from UserActionPerUserResult e JOIN UserActionPerUserResult.emailMessages e1 WHERE e.id = 1 and e.userAction = 1", UserActionPerUserResult.class);
List<UserActionPerUserResult> resultList = messagesQuery.getResultList();
Try writing the query like this:
TypedQuery<UserActionPerUserResult> messagesQuery = entityManager.createQuery(
"SELECT e from UserActionPerUserResult e JOIN FETCH e.emailMessages em WHERE e.id = 1 and e.userAction.id = 1", UserActionPerUserResult.class);
List<UserActionPerUserResult> resultList = messagesQuery.getResultList();
The join is using the root entity alias
The userAction.id is used against userAction, when matching against a numerical value
This HQL results in the tremendously helpful "error in named query" message
"FROM courseform c WHERE c.application.application IN
(SELECT a.application FROM application a WHERE a.applicant=: applicant)"
The CourseForm has a OneToOne unidirectional relationship with the Application (this could potentially be made bidirectional if it would help). Application in turn has the same unidirectional OneToOne relationship with the Applicant. One applicant can have many applications.
Here are the (abridged) definitions
CourseForm
#Entity
#NamedQueries({
#NamedQuery(name = "CourseForm.findByApplicant",
query = "FROM courseform c WHERE c.application.application IN
(SELECT a.application FROM application a WHERE a.applicant=: applicant)") })
public class CourseForm implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long id;
#Enumerated(EnumType.STRING)
private Career career;
private String academicPlan;
private String courseName;
#Enumerated(EnumType.STRING)
private ModeOfAttendance modeOfAttendance;
#OneToOne
#JoinColumn(name = "application_fk")
private Application application;
...
}
Application
#Entity
public class Application implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long applicationNumber;
#OneToOne
#JoinColumn(name = "applicant_fk")
private Applicant applicant;
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime")
private LocalDateTime lastUpdate = LocalDateTime.now();
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDateTime")
private LocalDateTime submitted = null;
public Application() {
}
Applicant
#Entity
#NamedQueries({ #NamedQuery(name = "Applicant.findByApplicantID",
query = "FROM Applicant a WHERE a.applicantID= :applicantID") })
public class Applicant implements Serializable {
private static final long serialVersionUID = -7210042752148566673L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
long id;
private String applicantID;
Applicant() {
}
Ok, according to Mark, right answer is
FROM courseform c WHERE c.application.applicant =: applicant
I think the error is with FROM courseform c WHERE c.application.application.You have used c.application.application in where clause
It should be FROM courseform c WHERE c.application
You can change to:
FROM courseform c WHERE c.application.applicationNumber IN (SELECT a.applicationNumber FROM application a WHERE a.applicant=: applicant)