Passing Queries from Postgres to JPA - java

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

Related

Hibernate Exception - could not locate named parameter

i am trying to extract a list of objects from database from entity (table) StudySeries:
#Entity
#Table(name="StudySeries", uniqueConstraints = {
#UniqueConstraint(columnNames = "SeriesInstanceUID")})
public class StudySeries implements Serializable {
...
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "SeId", unique = true, nullable = false)
private Long seId;
#Column(name="SeriesInstanceUID", unique=true, nullable = false)
private String seriesInstanceUID;
...
#ManyToOne
#JoinColumn(name = "StId", referencedColumnName="StId")
private StudyDetails studyDetails;
...
}
This entity is N-1 joined with StudyDetails (on StudyDetails has many StudySeries):
#Entity
#Table(name="StudyDetails", uniqueConstraints = #UniqueConstraint(columnNames = "StudyInstanceUID"))
public class StudyDetails implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name="StId", unique = true, nullable = false)
private Long stId;
#Column(name="StudyInstanceUID", unique=true, nullable = false)
private String studyInstanceUID;
...
#OneToMany(fetch = FetchType.LAZY, mappedBy = "studyDetails", cascade = CascadeType.ALL)
private Set<StudySeries> studySeries = new HashSet<StudySeries>(0);
...
}
In my StudySeriesDAOImpl() i am trying to:
#Override
public List<StudySeries> getStudySeriesObjectsByStudyId(Long stId) {
List<StudySeries> results=new ArrayList<>();
Session s=HibernateUtil.openSession();
s.beginTransaction();
String hql = "from StudySeries E where E.studyDetails.stId = stId";
Query query = s.createQuery(hql);
query.setParameter("stId", stId);
results = query.list();
s.getTransaction().commit();
s.close();
log.info(">>>>> list size: " + results.size());
return results;
}
I have also tried the hql query as:
String hql = "from StudySeries E where E.stId = stId";
However i am getting:
org.hibernate.QueryParameterException: could not locate named parameter [stId]
at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterDescriptor(ParameterMetadata.java:100) at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterDescriptor(ParameterMetadata.java:100)
at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterExpectedType(ParameterMetadata.java:106)
at org.hibernate.internal.AbstractQueryImpl.determineType(AbstractQueryImpl.java:466)
at org.hibernate.internal.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:436)
at com.npap.dao.StudySeriesDAOImpl.getStudySeriesObjectsByStudyId(StudySeriesDAOImpl.java:239)
Any ideas what is wrong?
In the StudySeries class, the id is named as 'seId', not 'stId'.
You should do like this: String hql = "from StudySeries E where E.seId = stId";

Hibernate with SqlServer performance drop on select

I have a performance issue with the following Hibernate TypedQuery:
select generatedAlias0 from MyClass1 as generatedAlias0
where generatedAlias0.class2.uid in (:param0, ..., :paramN)
Following the actual implementation this results in the following query:
select myclass1_.id, myclass1_.other, ... # 16 fields in total, no special big ones
from myschema.dbo.TblMyClass1 myclass1_ cross join myschema.dbo.TblMyClass2 myclass2_
where myclass1_.myclass2Id=myclass2.Id and (myclass2_.uid in('value1', ... 'valueN'))
Where N each time stands for 384 items.
When I execute this query in Toad it only takes about 150ms, but executed from code it takes almost a minute!
Class mappings
#Entity
#Table(name = "TblMyClass1", catalog = "myschema", schema = "dbo")
public class MyClass1 implements Serializable {
private static final long serialVersionUID = 8208493383744288872L;
#Id
#Column(name = "Id")
#GeneratedValue(strategy = GenerationType.AUTO)
protected Integer id;
#NotNull
#ManyToOne
#JoinColumn(name = "myclass2Id", referencedColumnName = "Id", nullable = false)
private MyClass2 class2 = null;
#NotNull
#ManyToOne
#JoinColumn(name = "myclass3Id", referencedColumnName = "Id", nullable = false)
private MyClass3 class3 = null;
#NotNull
#ManyToOne
#JoinColumn(name = "myClass4Id", referencedColumnName = "Id", nullable = false)
private MyClass4 myClass4;
#ManyToOne
#JoinColumn(name = "myClass5Uid", referencedColumnName = "UID", nullable = true)
private MyClass5 resultType;
#Column(name = "string2", nullable = true)
private String string2;
// other column fields and getters and setters ...
}
#Entity
#Table(name = "TblMyClass2", schema = "myschema", catalog = "dbo")
public final class MyCLass2 implements Serializable {
private static final long serialVersionUID = 4660579327140751989L;
#Id
#Column(name = "Id")
#GeneratedValue(strategy = GenerationType.AUTO)
protected Integer id;
#Column(name = "uid", nullable = false, updatable = false, unique = true)
private String uid;
// ... other columns fields and getters and setters
}
I only provided the mappings for the two classes in the slow query, since the follow-up queries of hibernate which fill all other linked entities all perform very good.
Using Java VisualVm I find that the following method takes 99% of the time:
com.microsoft.sqlserver.jdbc.TDSChannel.read()
I am running SQL Server 2008 and using sqljdbc4-2.0 and hibernate4.2.1 with spring3.2.9 (for transaction management)
Any help would be greatly appreciated !

JPQL : How to construct a WHERE clause?

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.

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