Join Entity with table that has no entity assosiated in JPQL - java

I have a table that has no associated Entity. I need to write JPQL query which will filter by that table's fields. Is it possible?
I know that I can do one of the following:
Create an Entity for that table( but it's basically a join table, so it will look strange to create an Entity class for it)
Write a native query( I don't like this approach either. If I use JPA, I must use JPQL only).
Create fully functional ManyToMany mapping( I just don't need it).
Could there be another approach?

Unfortunately you cannot do that with JPQL.
You should use SQL.
But a native query can also return Entities. Either if the returned values matches the entity or using #SqlResultSetMapping as described here:
http://javaee.support/sample/jpa-native-sql-resultset-mapping/
If you only need to join to entities on a relationship that is not mapped JPA 2.1 is able to JOIN on any table columns.

The problem was that I did not need a real many-to-many object mapping but only collection of id's in my only entity. So I came to following solution:
#ElementCollection
#CollectionTable(
name="user_to_feed",
joinColumns = #JoinColumn(name = "feed_id",referencedColumnName = "id")
)
#Column(name="user_id")
private List<Integer> userIds = new ArrayList<>();
This allows me to make following query:
select f.url from Feed f join f.userIds u where :id in u

Related

JPA mapping - composite FK with date-range

I am trying to solve following problem:
I have one table of ORDERS that contains: group of goods, type of goods and order date...this refers to table with GOODS, where group, type and valid-from is the PK + valid-to field.
I had a dream, that I can map goods to orders using JPA to save multiple SQL queries.
I believe I can basically use following aproach to map the composite relationship:
#JoinColumns({
#JoinColumn(name = "heilgruppe", referencedColumnName = "heilgruppe"),
#JoinColumn(name = "code", referencedColumnName = "heilmittel_code")
})
But I have troubles with the date attribute...because I obviously cannot just use "equals" to map one date field to another...I need to select such goods, where date of the order lies between valid-from and valid-to dates
But how to do it with JPA? Is it even possible to do it? Or am I forced to create new SQL query later in code to retrive required info?
Don't use composite PK in GOODS, but a technical ID (maybe generated) and you will avoid that problem and use this PK in ORDERS.
Or use the all GOODS composite PK in ORDERS and add valid-from in ORDERS (but it not the best way).

How to select in Hibernate criteria if there is no relationship between the tables? [duplicate]

I'd like to use Hibernate's criteria api to formulate a particular query that joins two entities. Let's say I have two entities, Pet and Owner with a owner having many pets, but crucially that association is not mapped in the Java annotations or xml.
With hql, I could select owners that have a pet called 'fido' by specifying the join in the query (rather than adding a set of pets to the owner class).
Can the same be done using hibernate criteria? If so how?
Thanks,
J
This is indeed possible with criteria:
DetachedCriteria ownerCriteria = DetachedCriteria.forClass(Owner.class);
ownerCriteria.setProjection(Property.forName("id"));
ownerCriteria.add(Restrictions.eq("ownername", "bob"));
Criteria criteria = getSession().createCriteria(Pet.class);
criteria.add(Property.forName("ownerId").in(ownerCriteria));
Update: This actually performs a sub-query instead of a join but it allows you to use Criteria on two entities that do not have a hibernate relationship defined.
My understanding is that if you do this using HQL, you are creating a Cartesian join with a filter, rather than an inner join. Criteria queries do not support doing this.
In NHibernate you can use subqueries which are defined as DetachedCriteria. Not sure if it works the same in Java, most probably it is the same:
DetachedCriteria pets = DetachedCriteria.For<Pet>("pet")
.SetProjection(Projections.Property("pet.ownername"))
.Add(/* some filters */ );
session.CreateCriteria(typeof(Owner))
.Add(Subqueries.PropertyIn("name", pets);
Assumed that it is joined using the name of the owner.
Criterion ownerCriterion = Restrictions.sqlRestriction(SELECT ownerId FROM Owner WHERE ownerName ='bob');
Criteria criteria = getSession().createCriteria(Pet.class);
criteria.createCriteria("ownerId").add(ownerCriterion);
There's a SQLCriterion, which you can give arbitrary SQL, and add to your Criteria. In the SQL string, the token {alias} "will be replaced by the alias of the root entity."

Hibernate #OneToOne mapping with a #Where clause

Will this work -
#OneToOne()
#JoinColumn(name = "id", referencedColumnName = "type_id")
#Where(clause = "type_name = OBJECTIVE")
public NoteEntity getObjectiveNote() {
return objectiveNote;
}
This is what I am trying to do - get the record from table note whose type_id is the id of the current object and type_name is OBJECTIVE.
I can't get the above mapping to work. What am I doing wrong here?
This just plain does not work, sorry :( You will need to do it as one to many and live with getting a collection with a single element.
If you really want it to work this way, you can trick hibernate by storing both the foreign key ID and the type_name in a join table and telling it that both columns make up the foreign key.
Actually you can achieve this by specifying #OneToOne without any #Where, but putting #Where on the referenced entity class. I tested this on Hibernate 4.3.11.
This works if you don't care about any entity objects that do not match your #Where.
If you do care about other entities, you can probably create a subclass entity, put #Where on it and join that subclass. But I have not tested this scenario.

JPA 2 -- Using #ElementCollection in CriteriaQuery

#Entity
public class Person {
#ElementCollection
private List<Location> locations;
[...]
}
#Embeddable
public class Location {
private Integer dummy;
private Date creationDate;
[...]
}
Given the following structure, I'd like to perform the HQL or CriteriaQuery equivalent of the following SQL:
SELECT
l.*
FROM
Location l
INNER JOIN
Person p ON (p.id = l.person_id)
WHERE
p.id = ? AND l.creationDate > ?
I want to get back a list of Locations that are associated with the given person and whose creationDate is after the given one.
Thanks in advance!
Mark
Edit***: I have edited the SQL, as it was kinda misleading. I don't want to query for the locations independently.
This is not possible, you cannot query an Embeddable. From the JPA Wikibook:
Embedded Collections
An ElementCollection mapping can be
used to define a collection of
Embeddable objects. This is not a
typical usage of Embeddable objects
as the objects are not embedded in the
source object's table, but stored in a
separate collection table. This is
similar to a OneToMany, except the
target object is an Embeddable
instead of an Entity. This allows
collections of simple objects to be
easily defined, without requiring the
simple objects to define an Id or
ManyToOne inverse mapping.
ElementCollection can also override
the mappings, or table for their
collection, so you can have multiple
entities reference the same Embeddable
class, but have each store their
dependent objects in a separate table.
The limitations of using an
ElementCollection instead of a
OneToMany is that the target
objects cannot be queried,
persisted, merged independently of
their parent object. They are strictly
privately-owned (dependent) objects,
the same as an Embedded mapping.
There is no cascade option on an
ElementCollection, the target
objects are always persisted, merged,
removed with their parent.
ElementCollection still can use a
fetch type and defaults to LAZY the
same as other collection mappings.
To achieve what you want, use a OneToMany and an Entity instead of an ElementCollection and an Embeddable. Or change your approach and query the Person.
The key phrase in Pascal's reply is
the target objects cannot be queried, persisted, merged independently of their parent object
As you are dependent on the parent object, you should be able to do this using something like ...
SELECT p FROM PERSON, IN (p.locations) WHERE p.id = ?1 AND locations = ?2
(Based on the reply at Execute "MEMBER OF" query against 'ElementCollection' Map fields in JP-QL (JPA 2.0) - which is actually a Map #ElementCollection which was what I was looking for an answer to!)

Hibernate criteria: Joining table without a mapped association

I'd like to use Hibernate's criteria api to formulate a particular query that joins two entities. Let's say I have two entities, Pet and Owner with a owner having many pets, but crucially that association is not mapped in the Java annotations or xml.
With hql, I could select owners that have a pet called 'fido' by specifying the join in the query (rather than adding a set of pets to the owner class).
Can the same be done using hibernate criteria? If so how?
Thanks,
J
This is indeed possible with criteria:
DetachedCriteria ownerCriteria = DetachedCriteria.forClass(Owner.class);
ownerCriteria.setProjection(Property.forName("id"));
ownerCriteria.add(Restrictions.eq("ownername", "bob"));
Criteria criteria = getSession().createCriteria(Pet.class);
criteria.add(Property.forName("ownerId").in(ownerCriteria));
Update: This actually performs a sub-query instead of a join but it allows you to use Criteria on two entities that do not have a hibernate relationship defined.
My understanding is that if you do this using HQL, you are creating a Cartesian join with a filter, rather than an inner join. Criteria queries do not support doing this.
In NHibernate you can use subqueries which are defined as DetachedCriteria. Not sure if it works the same in Java, most probably it is the same:
DetachedCriteria pets = DetachedCriteria.For<Pet>("pet")
.SetProjection(Projections.Property("pet.ownername"))
.Add(/* some filters */ );
session.CreateCriteria(typeof(Owner))
.Add(Subqueries.PropertyIn("name", pets);
Assumed that it is joined using the name of the owner.
Criterion ownerCriterion = Restrictions.sqlRestriction(SELECT ownerId FROM Owner WHERE ownerName ='bob');
Criteria criteria = getSession().createCriteria(Pet.class);
criteria.createCriteria("ownerId").add(ownerCriterion);
There's a SQLCriterion, which you can give arbitrary SQL, and add to your Criteria. In the SQL string, the token {alias} "will be replaced by the alias of the root entity."

Categories

Resources