hibernate one to one join using primary key not working - java

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.

Related

JPA/Hibernate Join only one selected column

To the existing table through #ManyToOne
#ManyToOne
#JoinColumns({
#JoinColumn(name = "ID", referencedColumnName = "APPLICATION_ID", insertable = false, updatable = false),
#JoinColumn(name = "VERSION", referencedColumnName = "APPLICATION_VERSION", insertable = false, updatable = false)
})
private ApplicationsBodies applicationsBodies;
I join another table.
But from the join table, I want to join only one column.
#Entity
#Table
public class ApplicationsBodies implements Serializable {
...
#Column(name = "APPLICATION_ID")
private Long applicationId;
#Column(name = "APPLICATION_VERSION")
private Long applicationVersion;
//I want to attach only this column
#Lob
#Column(name = "BODY")
private String body;
#Column(name = "ACTIVE_STATE")
private Integer activeState;
How can this be implemented using JPA / Hibernate?
UPDATE: Solution
My problem was solved by #Formula annotation. Because When I refer to an entity only for the purpose of loading this one field, for me it has become the most optimal solution.
I deleted the field: private ApplicationsBodies applicationsBodies. And created a field: private String body with annotation #Formula with value - SQL query joining only one column.
if you want to use join with JPA data, then I recommend to use JPL Query Language. So in your repository classes use as annotation :
#Query("select a.name from ApplicationsBodies a join a.applicationId d where d.id = :applicationVersion")

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

JPAQuery join intermediate many to many table

I'm using QueryDSL JPA, and want to do a join between two tables. I found many similar questions here already, but my case is different from all of them by one little detail. Here is a simplified version of my classes:
#Entity(name = "TABLE_A")
public class TableA {
#Id
#Column(name = "ID_A", nullable = false)
private Long idA;
}
#Entity(name = "TABLE_B")
public class TableB {
#Id
#Column(name = "ID_B", nullable = false)
private Long idB;
}
#Entity(name = "TABLE_C")
public class TableC {
#Id
#Column(name = "ID_C", nullable = false)
private Long idC;
#JoinColumn(name = "ID_A", referencedColumnName = "ID_A")
#ManyToOne
private TableA tableA;
#JoinColumn(name = "ID_B", referencedColumnName = "ID_B")
#ManyToOne
private TableB tableB;
}
Now what I want to do is join Tables A, C and B, to find the Bs which are linked to A. I know this seems like a useless step between, why not add a relation from A to B directly. In my case this is needed, these are just example classes to illustrate.
I tried this:
QTbTableA tableA = QTbTableA.tableA;
QTbTableB tableC = QTbTableC.tableC;
JPAQuery query = new JPAQuery(entityManager).from(tableA);
query.leftJoin(tableA, tableC.tableA);
The join throws an Exception because tableC.tableA is not a root path, only a property. But how do I join these tables correctly then?
Thanks in advance!
If you want to keep your current impl, you could start from TableC and then join the other tables:
query.from(tableC)
.innerJoin(tableC.tableA, tableA)
.innerJoin(tableC.tableB, tableB)
.where(tableA.idA.eq(myId)
.list(tableB);

JPA #ManyToMany ordering failure using #OrderBy

When JPA tries to select AdmUser entity I have sql error:
ERROR: column locations1_.name does not exist.
Is there anything wrong with my entities? My AdmUser entity:
#Entity
#Table(name = "ADM_USERS")
#SequenceGenerator(name = "ADM_USER_SEQ", sequenceName = "ADM_USER_SEQ", allocationSize = 1)
public class AdmUser implements EntityInt, Serializable {
private static final long serialVersionUID = 786L;
#Id
#Column(nullable = false)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ADM_USER_SEQ")
private Long id;
(...)
#ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
#JoinTable(name = "loc_locations_adm_users", joinColumns = #JoinColumn(name = "id_user", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name = "id_location"))
#OrderBy("name")
private Set<LocLocation> locations;
(...)
}
My LocLocation Entity:
#Entity
#Table(name = "loc_locations", schema = "public")
#SequenceGenerator(name = "LOC_LOCATIONS_SEQ", sequenceName = "LOC_LOCATIONS_SEQ", allocationSize = 1)
public class LocLocation implements EntityInt, java.io.Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id", unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "LOC_LOCATIONS_SEQ")
private Long id;
#Column(nullable = false, unique = true, length = 200)
private String name;
(...)
#ManyToMany(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY, mappedBy="locations")
private List<AdmUser> users;
}
And now - when JPA tries to select AdmUser entity I have sql error. The query generated by JPA looks that:
select
admuser0_.id as id1_2_0_,
admuser0_.actived as actived2_2_0_,
admuser0_.admin as admin3_2_0_,
admuser0_.allow_ip as allow_ip4_2_0_,
admuser0_.created as created5_2_0_,
admuser0_.deleted as deleted6_2_0_,
admuser0_.id_domain as id_doma16_2_0_,
admuser0_.email as email7_2_0_,
admuser0_.language as language8_2_0_,
admuser0_.login as login9_2_0_,
admuser0_.name as name10_2_0_,
admuser0_.passwd as passwd11_2_0_,
admuser0_.phone as phone12_2_0_,
admuser0_.picture as picture13_2_0_,
admuser0_.surname as surname14_2_0_,
admuser0_.theme as theme15_2_0_,
locations1_.id_user as id_user1_2_1_,
loclocatio2_.id as id_locat2_6_1_,
loclocatio2_.id as id1_17_2_,
loclocatio2_.description as descript2_17_2_,
loclocatio2_.name as name3_17_2_
from
public.ADM_USERS admuser0_
left outer join
public.loc_locations_adm_users locations1_
on admuser0_.id=locations1_.id_user
left outer join
public.loc_locations loclocatio2_
on locations1_.id_location=loclocatio2_.id
where
admuser0_.id=1
order by
locations1_.name
The order by points to locations1_.name, but should be loclocatio2_.name. Have I anything wrong with my entities?
You have a Set on one side for that field. Consequently there is no "ordering" (other than what hashCode() gves). Use a List if you want ordering (this is Java, nothing to do with JPA really).
You also seem to be missing a "mappedBy" on the non-owner side of that M-N.
The #OrderBy works fine with ManyToMany. Also with the structure I provided in my question. The problem was my query and JPA didn't managed with it. Sorry.

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.

Categories