JPQL : How to construct a WHERE clause? - java

i would like to create a namedquery in JPQL, but i don't understand how it's working...
Here my entity:
#Entity
#NamedQueries({
#NamedQuery(name = "Translation.lang",
query = "SELECT t FROM Translation t WHERE t.reference.id = :refId AND t.language.lang = :lang")
})
#Table(name = "T_E_TRANSLATION_TRL")
public class Translation implements java.io.Serializable {
#Id
#Column(name = "TRL_ID", unique = true, nullable = false)
#TableGenerator(name="translationSeqStore",
table="T_S_APP_SEQ_STORE_AST",
pkColumnName="AST_SEQ_NAME",
valueColumnName = "AST_SEQ_VALUE",
pkColumnValue = "T_E_TRANSLATION_TRL.TRL_ID",
allocationSize=1)
#GeneratedValue(strategy=GenerationType.TABLE,
generator="translationSeqStore")
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRL_REF_ID", nullable = false)
private Reference reference;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRL_LAN_ID", nullable = false)
private Language language;
#Column(name = "TRL_LABEL", nullable = false, length = 4000)
private String label;
Should i use LEFT JOIN on Reference & Language to select my translatation with these id ?
Thank you.

I think you want:
SELECT t FROM Translation t join fetch t.reference join fetch t.language WHERE t.reference.id = :refId AND t.language.lang = :lang
That will join (and fetch the LAZY reference and language) and return the Translations for the reference with ID refId and language with lang = lang.

Related

Passing Queries from Postgres to JPA

I'm newbie
I'm trying pass this Postgres query to JPA/JPQL
SELECT
DISTINCT(srv.code) AS Serv_Cod,
srv.id AS Serv_id,
srv.description AS Serv_Desc
FROM db.Category AS cat
join db.Classification AS cla ON cat.id = cla.cat_id
join db.Service AS srv ON srv.id = cla.srv_id
WHERE cat.id = 10
ORDER BY srv.id;
Now I want to write the same Query, I have the Entities with the same name Table.
Classification
#Entity
#Table(name = "Classification", schema = "db")
#Audited
public class Classification implements Identifiable<Long> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "srv_id", nullable = true)
private Service service;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "cat_id", nullable = true)
private Category category;
....
}
Service
#Entity
#Table(name = "Service", schema = "db")
#Audited
public class Service implements Identifiable<Long> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "code", nullable = false)
private String code;
#Column(name = "description", nullable = false)
private String description;
....
}
I was reading, but I'm very confused...
I don't know how to write the ON for the JOIN, and establish the DISTINCT for a Column/Field.
Long myID = 25L;
this.em.createQuery("SELECT NEW SomeDto(srv.id, srv.code, srv.description)"
+ " FROM Classification cla"
+ "JOIN cla·cat_id cat"
+ "JOIN cla·srv_id srv"
+ "WHERE cat.id = :id"
,BaseObjectDto.class).setParameter("id", myID).getResultList();
Thank you for you valuable Help.
The query is very simple. When you have ToOne relationships you can navigate to the related entity. There is no need to JOIN ON.
Even with ToMany there is no need for the ON because this is already defined in the mapping.
So the query will look like:
SELECT NEW SomeDto(cla.service.id, cla.service.code, cla.service.description)
FROM Classification cla
WHERE category.id = :id

hibernate one to one join using primary key not working

I have 2 entities in hibernate A and B. Here is the relevant code.
#Entity
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Integer id;
#OneToOne(mappedBy = "a", cascade = CascadeType.ALL)
private B b;
}
#Entity
public class B {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Integer id;
#Column(name = "a_id")
#GeneratedValue(generator = "gen")
#GenericGenerator(name = "gen", strategy = "foreign", parameters = #Parameter(name = "property", value = "a"))
private Integer aId;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#PrimaryKeyJoinColumn
private A a;
}
I did the same as mentioned in the below mentioned link
one to one mapping using primary key join column
However, when I do the following hql query,
"from A a left join a.b"
the join is taken on the following condition
a.id = b.id
although what I desire is the following condition
a.id = b.aId
You must use #JoinColumn(name = "a_id") instead of #PrimaryKeyJoinColumn.
By the way, you can't define two fields on the same column. However, if you need to do so you must make one of them not insertable and not updateable like this:
#JoinColumn(name = "a_id", insertable = false, updatable = false)
You have given the reference of class A to field a in class B.
#OneToOne(fetch = FetchType.LAZY, optional = false)
#PrimaryKeyJoinColumn
private A a;
And class B to field b in class A
#OneToOne(mappedBy="a", cascade=CascadeType.ALL)
private B b;
so by default Hibernate create a join query with referenced field. So hibernate by default perform the join on a.id = b.id.
But i think you can create your own query and use native query for performing join with a.id = b.aId.

#SqlResultSetMapping columns : entities with sub-entities

I have Test entity :
public class Test {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "duration", nullable = false)
private int duration;
#Column(name = "test_name", nullable = false, unique = true)
private String testName;
#Column(name = "archived", nullable = false)
private boolean archived;
#OneToMany(mappedBy = "test", fetch = FetchType.EAGER)
private Set<Question> questions;
#ManyToMany(mappedBy = "tests")
private Set<User> users;
Question Entity:
public class Question {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "is_multichoice", nullable = false)
private boolean isMultichoice;
#Column(name = "is_open", nullable = false)
private boolean isOpen;
#Column(name = "picture")
private String picture;
#Column(name = "question")
private String question;
#ManyToOne
#JoinColumn(name = "test_id", nullable = false)
private Test test;
#Column(name = "archived", nullable = false)
private boolean isArchived;
#OneToMany(mappedBy = "question", fetch = FetchType.EAGER)
private Set<Answer> answers;
This Test entity has Set of questions, in such way Question Entity has Set of answers.
I wrote SQL query to get test (The reason why it is not HQL you could find by link Hibernate HQL : no entity found for query) :
#NamedNativeQuery(name = "getCurrentTestById",
query = "SELECT t.id as tId, t.test_name, t.duration, q.id as qId, " +
"q.question as question, q.is_multichoice as is_multichoice, " +
"q.is_open as is_open, a.id as aId, a.answer_text as answer_text FROM result r " +
"JOIN test t ON r.test_id = t.id " +
"JOIN user u ON r.user_id = u.id " +
"JOIN question q ON t.id = q.test_id JOIN answer a ON q.id = a.question_id " +
"WHERE t.id = :testId AND u.id = :userId AND r.permission = :permissionId " +
"AND q.archived = false AND a.archived = false")
Now i need to map it to my entity Test by using #SqlResultSetMapping annotation:
#SqlResultSetMappings({
#SqlResultSetMapping(name="toTest",
entities = {
#EntityResult(entityClass = com.bionic.entities.Test.class, fields = {
#FieldResult(name = "id", column = "tId"),
#FieldResult(name = "test_name", column = "test_name"),
#FieldResult(name = "duration", column = "duration"),
#FieldResult(name = "questions.question", column = "question"),
#FieldResult(name = "questions.id", column = "qId"),
#FieldResult(name = "questions.isMultichoice", column = "is_multichoice"),
#FieldResult(name = "questions.isOpen", column = "is_open"),
#FieldResult(name = "questions.answers.id", column = "aId"),
#FieldResult(name = "questions.answers.answer_text", column = "answer_text"),
})
})
})
I am getting exception :
Caused by: org.hibernate.MappingException: dotted notation reference neither a component nor a many/one to one
This is why frameworks are generally bad news. Instead of using hibernate, you should follow the interface segregation principle. Your application should not know or care about How to select the data you need and what the table names are etc. Simply create a stored procedure that takes this responsibility and call it as opposed to having all the junk code in your app. Then if you want an easy way to map just have your stored proc return json by calling For JSON at the end. Mapping object fields to the JSON object becomes a piece of cake. You will find that with frameworks you spend more time troubleshooting the framework than actually programming.

Hibernate query causing lots extra unnecassery queries

I am developing a auction site. The problem lies in 3 entities i use:
Product (has zero or many ProductBid)
ProductBid (has zero or one ProductBidRejection)
ProductBidRejection
I use a hibernate query to get the bids:
select pb from ProductBid pb left join pb.rejection pbr where pbr is null and pb.product = :product order by pb.amount desc
This generates this query (via console):
select
productbid0_.id as id4_,
productbid0_.amount as amount4_,
productbid0_.bid_by as bid4_4_,
productbid0_.date as date4_,
productbid0_.product_id as product5_4_
from
product_bids productbid0_
left outer join
product_bid_rejections productbid1_
on productbid0_.id=productbid1_.product_bid_id
where
(
productbid1_.id is null
)
and productbid0_.product_id=?
But for each bid it gets it also generates:
select
productbid0_.id as id3_1_,
productbid0_.date_rejected as date2_3_1_,
productbid0_.product_bid_id as product4_3_1_,
productbid0_.reason as reason3_1_,
productbid0_.rejected_by as rejected5_3_1_,
productbid1_.id as id4_0_,
productbid1_.amount as amount4_0_,
productbid1_.bid_by as bid4_4_0_,
productbid1_.date as date4_0_,
productbid1_.product_id as product5_4_0_
from
product_bid_rejections productbid0_
inner join
product_bids productbid1_
on productbid0_.product_bid_id=productbid1_.id
where
productbid0_.product_bid_id=?
These are my entities:
ProductBid
#Entity
#Table(name = "product_bids")
public class ProductBid
{
#Column(name = "id", nullable = false)
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#JoinColumn(name = "product_id", nullable = false)
#Index(name="product")
#ManyToOne(fetch = FetchType.LAZY)
private Product product;
#Column(name = "amount", nullable = false)
private BigDecimal amount;
#JoinColumn(name = "bid_by", nullable = false)
#Index(name="bidBy")
#ManyToOne(fetch = FetchType.LAZY)
#Fetch(FetchMode.JOIN)
private User bidBy;
#Column(name = "date", nullable = false)
#Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
private DateTime date;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "productBid")
private ProductBidRejection rejection;
}
ProductBidRejection
#Entity
#Table(name = "product_bid_rejections")
public class ProductBidRejection
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private long id;
#Column(name = "reason", nullable = false, columnDefinition = "TEXT")
private String reason;
#Column(name = "date_rejected", nullable = false)
#Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
private DateTime dateRejected;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "rejected_by", nullable = false)
private User rejectedBy;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "product_bid_id", nullable = false)
#Fetch(FetchMode.JOIN)
private ProductBid productBid;
}
Its because you have #Fetch(FetchMode.JOIN) on ProductBid.
So for each of the ProductBidRejections you retrieve, it also loads a ProductBid.
UPDATE
Try this query. It will get distinct pb and eagerly fetch the PBR
select distinct pb from ProductBid pb left join fetch pb.rejection pbr where pbr is null and pb.product = :product order by pb.amount desc
Use Criteria instead of HQL your problem will be solve
session.createCriteria(ProductBid.class).add(Restrictions.eq("product",yourproduct)).list();
and in ProductBid Entity Class use annotation to join EAGER ly to ProductBidRejection

Java Persistence Query Language JOIN

I have two tables :
A(bigint id, ...)
B(bigint id, varchar name, bigint id_A)
and now I want get all rows from A which exists in B (and those rows in B have name eg Andy)
Plase help me create dynamic query
class A
#Entity
#Table(name = "A", schema = "mySchema")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public class A{
#Id
private Long id;
}
class B
#Entity
#Table(name = "B",
schema = "mySchema",
uniqueConstraints = { #UniqueConstraint(columnNames = {
"some_id", "id_A" }) })
public class B{
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "Seq")
#SequenceGenerator(name = "Seq", sequenceName = "mySchema.mySeq")
private Long id;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_A", nullable = false)
private A a;
#Column(name = "id_A", updatable = false, insertable = false)
private Long IdA;
}
There are several weird parts. e.g. this:
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_A", nullable = false)
private A a;
#Column(name = "id_A", updatable = false, insertable = false)
private Long IdA;
With the #JoinColumn annotation you are telling the JPA provider that it should use the specified column for internal mapping, but with the IdA field, you are trying to manage the column yourself. Which is it going to be?

Categories