I have two tables in my PostgreSQL database:
CREATE TABLE tableOne (id int, name varchar(10), address varchar(20))
CREATE TABLE tableTwo (id int, info text, addresses varchar(20)[])
now I want to create a join as follows:
SELECT * FROM tableOne JOIN tableTwo ON address = ANY(addresses)
I tried to achieve this using Hibernate - class TableOne:
#Entity
#Table(name = "tableOne")
class TableOne {
private int id;
private TableTwo tableTwo;
private String address;
#Id
#Column(name = "id")
public getId() { return id; }
#ManyToOne
#JoinFormula(value = "address = any(tableTwo.addresses)",
referencedColumnName = "addresses")
public TableTwo getTableTwo(){
return tableTwo;
}
// Setters follow here
}
But Hibernate keeps generating queries with non-sense JOIN clauses, like:
... JOIN tableTwo ON _this.address = any(tableTwo.addresses) = tableTwo.addresses
How do I tell Hibernate using annotations to format my join query correctly? Unfortunately, our project must be restricted only to the Criteria API.
EDIT:
After suggestion from ashokhein in the comments below, I annotated the method getTableTwo() with just #ManyToOne - and now I would like to do the join using Criteria API, presumably with createAlias(associationPath,alias,joinType,withClause) method where withClause would be my ON clause in the join.
But Im not sure what to put as associationPath and alias parameters.
Any hints?
To support PostgreSQL array you need a custom Hibernate Type. Having a dedicated user type will allow you to run native SQL queries to make use of the type:
String[] values = ...
Type arrayType = new CustomType(new ArrayUserType());
query.setParameter("value", values, arrayType);
HQL supports ANY/SOME syntax but only for sub-queries. In your case you'll need a native query to use the PostgreSQL specific ANY clause against array values.
You can try Named Query.
#NamedQuery(name="JOINQUERY", query="SELECT one FROM tableOne one JOIN tableTwo two ON one.address = :address" )
#Entity
class TableOne{......
Retrieving part is:
TypedQuery<TableOne> q = em.createNamedQuery("query", TableOne.class);
q.setParameter("address", "Mumbai");
for (TableOne t : q.getResultList())
System.out.println(t.address);
You might need to do some permutations on the query
So after a lot of time searching for the right answer, the only real solution that works for us is creating a view:
CREATE VIEW TableA_view AS SELECT TableOne.*,TableTwo.id FROM TableA JOIN TableTwo ON TableOne.address = ANY(TableTwo.addresses)
and mapping it to an entity TableOne instead of the original table.
This was the only solution for us besides, of course, using a named query, which was a no-go as we needed to stick to the Criteria API.
As #ericbn has mentioned in the comments this is really an example where ORM gets really annoying. I would never expect that custom join clause like this is not possible to do in Hibernate.
#JoinFormula should contain SQL instead of HQL.
https://docs.jboss.org/hibernate/orm/4.2/javadocs/org/hibernate/annotations/JoinFormula.html
Related
I want to create a querydsl Predicate to use it with spring-jpa CrudRepository.
Problem: I have an optional #PrimaryKeyJoinColumn that references to the child entity by #Id PK.
And I want to select only the rows where the child table does not contain a reference with the main row.
In this example: I only want to select bookings in status = 2, and where no editor reference exists inside the child table.
BooleanBuilder booleanBuilder = new BooleanBuilder(predicate)
.and(QBooking.booking.status.eq(2))
.and(QBooking.booking.editor.id.isNull());
dao.findAll(booleanBuilder.getValue()); //dao is QuerydslPredicateExecutor<Booking>
class Booking {
#Id
long id;
String status;
//joins the table by their PK id
#PrimaryKeyJoinColumn
public Editor editor;
}
class Editor {
#Id
long id;
...
}
The sql generated from it is:
select * from booking
CROSS JOIN editor
WHERE booking.id = editor.id
and booking.status = ?
and editor.id is null;
But this is wrong (as of course this never returns any result)!
What I'm looking for is:
select * from booking
CROSS JOIN editor
WHERE (booking.id = editor.id OR editor.id is null)
and booking.status = ?;
How can I achieve the later sql statement with querydsl?
You should be able to workaround the issue by using QBooking.booking.editor.isNull() instead, which is perfectly valid to do in JPQL. However, ID dereference should have just worked here, so you're probably looking at a bug in your ORM implementation. Probably upgrading to the latest version of Hibernate will resolve your issue as well.
I've stumbled upon a problem with Hibernate. I've 2 entities - let's say A and B like so (Entity/Table annotations ommited):
class A {
#ManyToOne
#JoinColumn(name = "b_id")
private B b;
}
class B {
#Column(name = "name")
private String name;
}
Now, I'm trying to query all A entities and ordering them by name field of B's entity like so:
SELECT q FROM A AS q ORDER BY q.b.name asc nulls last
The problem is, there are rows in A's table having null foreign-key (b is null) - in result the aforementioned query returns only rows that don't contain null in b field, and I'd like to have them all.
I guess hibernate joins the table without using LEFT JOIN (OUTER JOIN?) resulting in null values being skipped.
Is there any way to change this behaviour? It would be great, if I could solve it by using annotations in entity classes, because the query-generating mechanism is pretty locked up.
You can use CriteriaBuilder and set alias on entityRoot
Root<A> entityRoot = criteriaQuery.from(A);
entityRoot.join("b", JoinType.LEFT).alias("b");
criteriaQuery.select(entityRoot)
.orderBy(criteriaBuilder.asc(entityRoot.get("b").get("name"))
;
you can use criteria query for this but you will have to create session while using that, it is simpler to access database using criteria:
Criteria criteria = session.createCriteria(A.class)
//create alias of your other class to provide ordering according to foriegn key
criteria.createAlias("foreignkey","keyin table A(eg..b)");
criteria.addOrder(Order.asc(b.name));
List list = criteria.getlist();
hope this helps
I hve a table with a forign key like so:
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="BASE_ID", updatable = false)
private Base base;
Which connects to a Base table using its "id" .. I'm trying to query this with a where clause but i'm running into errors, my query looks like:
return getEntityManager()
.createQuery("SELECT a FROM BaseEventLog a join fetch a.base p WHERE p.eventStatus = 'ERROR'",
BaseEventLog.class)
.getResultList();
In sql it would look like this:
SELECT *
FROM BASE_EVENT_LOG
JOIN BASE
ON BASE.ID=BASE_EVENT_LOG.BASE_ID
WHERE EVENT_STATUS = 'ERROR'
Any suggestions on how to create such a query with jpsql ?
SELECT a FROM BaseEventLog a
join a.base p
WHERE p.eventStatus = 'ERROR'
No need for the fetch; or atleast I have never used it with JPQL. If you want to use the fetch keyword take a look out how to use it here:
http://docs.oracle.com/cd/E17904_01/apirefs.1111/e13946/ejb3_langref.html#ejb3_langref_fetch_joins
I'm new to JPA so forgive me if my question seems silly.
We have used JPA in our project. I see that every entity object has a direct mapping with a table and each row in the table is an object of that entity type.
But, suppose I only want to access one or two columns of a table, how do i go about doing it ? The reason I'm asking is because of the task i have in hand.
There are two tables. The first table has everything set up with JPA so that each row can be cast into an object type. The first table has a column that is referenced in the second table i.e. say, table A has column CLOTH_ID and Table B has columns CLOTH_ID and CLOTH_DESCRIPTION. CLOTH_ID is used in both Table A and B; But B has the CLOTH_DESCRIPTION columns which corresponds to CLOTH_ID.
I'm displaying Table A in my webpage but I also need to display : CLOTH_DESCRIPTION in my webpage. Is there a JPA oriented way to do this or Am i better off using regular JDBC to extract the CLOTH DESCRIPTION values ?
I assume you have the following setup:
#Entity
#Table(name="A")
class A {
#ManyToOne
#JoinColumn(name="CLOTH_ID")
private B cloth;
//...
}
#Entity
#Table(name="B")
class B {
#Id
#Column(name="CLOTH_ID")
private int id;
#Column(name="CLOTH_DESCRIPTION")
private String description;
//...
}
If you don't... you're doing it wrong (i.e. it is not idiomatic JPA usage). You have the following options:
Simply fetch A
In this case #ManyToOne relationship will be fetched eagerly by default as well. Then simply call in Java:
a.getCloth().getDescription()
Prefer this approach as it is the simplest and most idiomatic unless the number of columns in B is huge.
Use JPA query with custom columns:
SELECT a, a.b.description
FROM A a
WHERE a.id = :id
In this case the query returns List<Object[]>, where Object[] actually contains two elements: A and String.
Same as above but with custom DTO:
class Adto {
private final A a;
private final String description;
public Adto(A a, String description) {
this.a = a;
this.description = description;
}
}
And slightly modified query:
SELECT new Adto(a, a.b.description)
FROM A a
WHERE a.id = :id
How can I join two tables by using java play framework and jpa, I really have a hardtime converting my MySQL query to jpa query.
Here is the MySQL query that I used in my old Java code:
SELECT * FROM tbl_majors
INNER JOIN tbl_lookup_user_major
ON tbl_majors.id=tbl_lookup_user_major.majorId
WHERE tbl_lookup_user_major.userId=12
//Table 1:
#Entity
#Table(name="tbl_majors")
public class Major extends Model {
public Major(){
}
#Column(name="major_name")
private String name;
#Column(name="major_desc")
private String description;
}
//Table 2
#Entity
#Table(name="tbl_lookup_user_major")
public class LookupUserMajor extends Model {
public LookupUserMajor(){
}
private int majorId;
private int userId;
}
Dont know if I get the exact point here, but in the tutorial blog "YABE", this kind of join table is used and created automatically by Play :
http://www.playframework.org/documentation/1.2.4/guide6#tagging
The many-to-many relation is described in the Model (between "Post" and "Tag" here for the blog sample) :
#ManyToMany(cascade=CascadeType.PERSIST)
public Set<Tag> tags;
public Post(User author, String title, String content) {
...
this.tags = new TreeSet<Tag>();
...
this.title = title;
this.content = content;
...
}
The YAML for the Posts data is :
Post(jeffPost):
title: The MVC application
postedAt: 2009-06-06
author: jeff
tags:
- play
- architecture
- mvc
After running the app, I check the database and the table "post_tag" is automatically created and all the links between the two tables are done (post_ids and tags_ids are filled).
Retrieving data seems as easy as :
"select distinct p from Post p join p.tags as t"
Can someone confirm that ? Because new to Java and JPA and Play ^^
If this is correct, it looks easier than managing the join table "manually".
Every time you have a field names "xxxId" in an entity, and "xxxId" is the ID of another entity, you did something wrong. The point of JPA is to manipulate objects, and associations between objects using object references or object collections.
Your tbl_lookup_user_major looks like a join table to me. Such a join table means that you have a many-to-many (or one-to-many, is one of the IDs is unique) between Major and User. So, your Major entity should have the following field :
#ManyToMany
#JoinTable(...) // details omitted
private Set<User> users;
And your JPA query should look like
select m from Major m
inner join m.users user
where user.id = :userId
Example Jpa query try like this...
Query query = JPA.em().createQuery(" SELECT * FROM "+User.class.getName() +" AS a JOIN "+
Role.class.getName()+" AS b WHERE a.roleId=b.roleId ");