Can you specify date-based partition keys when joining to related entities? - java

I have two related entities being mapped by JPA annotations backed by hibernate. The entities both have sequence-backed identity columns in oracle. Our also have monthly partitions, represented by a column called ENTRY_DATE.
T_MASTER T_JOINED
--------- -----------
MASTER_ID JOINED_ID
ENTRY_DATE ENTRY_DATE
MASTER_ID(FK)
... ....
To gain the benefit of the partition key, I'd like Hibernate to join on both the identity IDs and the partition key, but when I use the following annotation in the Joined class:
#ManyToOne
#JoinColumns(value={
#JoinColumn(name="MASTER_ID"),
#JoinColumn(name="ENTRY_DATE")})
private Master master;
I get errors about having too many join columns. I am forced to use
#JoinColumn(name="MASTER_ID")
private Master master;
I'm a bit of a JPA/Hibernate noob. Is it possible to use a partition key in addition to the primary key when joining to related entities?
Thanks!

You probably need to declare both columns as parts of composite primary key in Master. Hibernate would not care that much about what is real PK in the database. Mapping wil be slightly more complex with #Embeddable but it should solve the problem.

yes.
Using native sql it looks as follows:
Query query = session.createSQLQuery( "SELECT {T_master.*}, {T_joined.*} FROM schema.t_master AS T_master OUTER LEFT JOIN schema.T_joined AS T_joined ON T_master.ENTRY_DATE = T_joined.ENTRY_DATE AND T_master.MASTER_ID = T_joined.JOINED ID " /*WHERE ... */ );
query.setEntity( "T_master", T_master.class);
query.setJoin( "T_joined", "T_master.joinedSet"); //joinedSet is the one-to-many mapping
query.setJoin( "T_master", "T_joined.master" );
Thus, you get to be very verbose on your query, and hibernate only acts as an object mapper.
Using Criteria or HQL, it is impossible to have OUTER LEFT JOIN ON some field other than primary keys. This is why if you have such an option, use native SQL code.

Related

QueryDSL, specify projection for join

I'm trying to use QueryDSL to fetch a collection of entities (table Category) where each entity has a #OneToMany association with an other type of entity (table User), and a join is used to get it all in one go.
Problem is that the second entity (the users) contains CLOB fields which should not be included. I don't want to include them in my query. Given the following QueryDSL query :
JPAQuery<CategoryEntity> baseQuery = new JPAQuery<>(entityManager)
.select(QCategoryEntity.categoryEntity)
.from(QCategoryEntity.categoryEntity)
.leftJoin(QCategoryEntity.categoryEntity.users, QUserEntity.userEntity)
.where(somePredicate);
QueryDSL will generate something like
SELECT categoryen0_.id, (...), useren0_.id, (...)
FROM category categoryen0
LEFT OUTER JOIN user useren0 ON ...
WHERE ...
How can a specific projection be applied to this query such that the CLOB data is excluded?
Notes :
I'm trying to avoid native queries and changing the domain model.
I have not found a way to use Projections on the join
itself.
Using subqueries inside joins is not supported by JPQL hence
it's not supported by QueryDSL either.
Turns out this was not working well due to my use of fetch joins, which prevented me from using projections. Solving it was a matter of using a basic join instead and manually reconstructing the relationship.
Collection<Tuple> tuples = new JPAQuery<>(entityManager)
.select(QCategoryEntity.categoryEntity, Projections.constructor(UserEntity.class, <constructor arguments>)
.from(QCategoryEntity.categoryEntity)
.join(QCategoryEntity.categoryEntity.users, QUserEntity.userEntity)
.where(somePredicate);

Spring framework data JPA Inner Join on multiple columns

I would like to do the following query using spring jpa. I am able to build the where clause for my statement with Predicate.toPredicate. However, I don't know how to join on more than one column. On a single column it can be done in the repository using #Query and #Param
SELECT a.name, a.column_x, b.column_y
FROM table_a a
INNER JOIN table_b b
ON b.name = a.name
AND b.pk_2 = a.pk_2
AND b.pk_3 = a.pk_3
WHERE ...;
Another question I have is, is an intermediate tableA_tableB association beneficial if I have something like this, oneToMany relations.
Table 1: thing
thing_name
type
tenant
other1
other2
Table 2: thing_sub_prop
prop_name
value
Association table: thing_thing_sub_prop
type
thing_name
tenant
prop_name
value
Or is it better to just have two tables, thing and thing_sub_prop with the primary key columns of thing repeated in thing_sub_prop as a foreign key?

Left join on unrelated tables in Query DSL and JPA

I have two unrelated tables, each one with field email. I need a query which introduces column taken from second table if emails match or will be null if no match is found. In SQL this is easy:
SELECT tableA.id, tableA.email, tableB.name
FROM tableA
LEFT JOIN tableB ON tableA.email=tableB.email
ORDER BY tableB.name
Unfortunately JPA doesn't allow joins over unrelated entities so I converted it to:
SELECT tableA.id, tableA.email,
(SELECT tableB.name FROM tableB WHERE tableB.email=tableA.email) AS aname
FROM tableA
ORDER BY aname
Now, it works as JPA query but we are using Query DSL so off we go to converting it:
JPQLQuery query = new JPAQuery(em);
List<Dto> items=query.from(qTableA)
.list(new QDto(qTableA.id, qTableA.email,
new JPASubQuery().from(qTableB)
.where(qTableB.email.eq(qTableA.email)).unique(qTableB.name)))
It works but now I have no idea how to implement sorting and filtering by field introduced by subquery.
Dto is a POJO used to collect results, QDto is a class autogenerated from Dto.
Question is: how to join two unrelated tables using Query DSL and JPA and avoiding native SQL? Is it possible? Sorting and filtering on fields from tableA and tableB.name is a requirement.
Join on unrelated entities is not covered by latest JPA spec (2.1)
However Hibernate 5.1.0+ and EclipseLink 2.4.0+ support ad hoc joins. http://blog.anthavio.net/2016/03/join-unrelated-entities-in-jpa.html

JQPL Update Query to update entity without using the primary key

This may be a simple question, but I'm trying to find out if there is a way that I can create a JPQL update query that would allow me to update a single Persisted Entity using a unique column identifier that is not the primary key.
Say I have and entity like the following:
#Entity
public class Customer {
#ID
private Long id;
#Column
private String uniqueExternalID;
#Column
private String firstname;
....
}
Updating this entity with a Customer that has the id value set is easy, however, id like to update this customer entity using the uniqueExternalId without having to pre-query for the local entity and merge the changes in or manually construct a jpql query with all the fields in it manually.
Something like
UPDATE Customer c SET c = :customer WHERE c.uniqueExternalId = :externalId
Is something like this possible in JQPL?
You cannot do it in the exact way you describe - by passing an entity reference, but you can use bulk queries to achieve the same effect.
UPDATE Customer c SET c.name = :name WHERE c.uniqueExternalId = :externalId
Please note that you will have to explicitly define each updated attribute.
It is important to note that bulk queries bypass the persistence context. Entity instances that are managed within the persistence context will not reflect the changes to the records that are changed by the bulk update. Further, if you use optimistic locking, consider incrementing the #Version field of your entities with the bulk update:
UPDATE Customer c SET c.name = :name, c.version = c.version + 1 WHERE c.uniqueExternalId = :externalId
EDIT: The JPA 2.0 spec advises in ยง 4.10:
In general, bulk update and delete operations should only be performed
within a transaction in a new persistence context or before fetching
or accessing entities whose state might be affected by such
operations.

JPA: Modelling m:n relationship & join-table values

having a m:n real-world relationship between some entities, e.g. user <---> group
Now I want to model this relationship and store additional information based on it, e.g. a field "quality".
I heard that I would have to create a new join table user_group as follows:
id | user_ref | group_ref | quality
----------------------------------
1 1 1 0.5
2 1 2 1.3
... ... ... ...
The corresponding entity has two related entities (private members) user and group, annotated with the #ManyToOne-annotation.
On the other hand, both, my user and my group have a set of related user_group-entities, both private members and declared with the #OneToMany-annotation.
I have three questions:
Is this the right way to model the problem of additional fields in JPA 2.0?
I not allowed to use both user and group in user_group as primary key
since they are not valid primary key types. Is it really necessary to declare a new primary.
Is this a common workflow with these join-tables/entities?
...
EntityManager em = ...
...
em.getTransaction().begin();
User u = new User("Pete");
Group g = new Group("Anonymous workaholics")
UserGroup ug = new UserGroup();
ug.addUser(u);
ug.addGroup(g);
em.persist(u); em.persist(g); em.persist(ug);
em.getTransaction().commit();
em.close()
Thanks a lot!
Yes, it's the good way to do it.
It's possible to have a composite primary key consisting of two ManyToOne associations, but it's much more complex, both in the mapping and in the rest of the application, to handle that, and it's also less efficient. You have an entity, so just do like for all the other entities and use an auto-generated, single-column primary key. The fact that this entity used to be a join table of a many-to-many association is irrelevant.
Yes, that seems OK, except the addUser() and addGroup() methods should be named setUser() and setGroup(): there's only one user and one group for a given UserGroup. I would also use another name for the entity itself. Something like "Membership" for example.

Categories