Could not resolve property of #OneToMany child table (#JoinColumn) - java

I am getting the above error when trying to run a custom query. I understand that with hibernate, you need to map to the entity names (not the column names). However, in the case of a #OneToMany, I don't have the column in the child. Let me explain with a simple example (I've removed all other columns and methods):
#Query("SELECT ch.randomColumnHere FROM Parent pa INNER JOIN Child ch ON pa.id = ch.parent_id")
Parent.class
#Entity(name="Parent")
#Table(name="parent")
#Builder(toBuilder = true)
#AllArgsConstructor(access = AccessLevel.PACKAGE)
#NoArgsConstructor
#Setter
#Getter
public class Parent {
#Id
#SequenceGenerator(name = "parent_id_seq", sequenceName = "parent_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "parent_id_seq")
private Long id;
#OneToMany (cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "parent_id", nullable = false, updatable = false)
private List<Child> children;
}
Child.class
#Entity(name="Child")
#Table(name="child")
#Builder(toBuilder = true)
#AllArgsConstructor(access = AccessLevel.PACKAGE)
#NoArgsConstructor
#Setter
#Getter
public class Child {
#Id
#SequenceGenerator(name = "child_id_seq", sequenceName = "child_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "child_id_seq")
private Long id;
#Column(name="randomcolumnhere")
private Double randomColumnHere;
}
I get the following exception:
Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: could not resolve property: parent_id
I understand that there is no field called parent_id in the Child entity. How can I get around this? Since the only 'reference' to the parent_id column is the #JoinColumn of the Parent class.
Any suggestions?

Add relationship in child class as follow and change query accordingly.
#ManyToOne
private Parent p;
#Query("SELECT ch.randomColumnHere FROM Parent pa INNER JOIN Child ch ON pa.id = ch.p.id")

HQL queries use entities and their associations. The fact that the association uses a join table or not is not important for HQL: you navigate through associations and Hibernate does the appropriate translation to SQL.
SELECT ch.randomColumnHere FROM Parent pa INNER JOIN pa.children;

Related

hibernate search 6 updating elasticsearch index after entity update

I have a problem using elasticsearch with hibernate search 6. Let's assume we have this setup :
#Entity
#Table(name = "entityA")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
#Indexed(index = "entityA")
public class EntityA {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
#GenericField
private Long id;
#Column(name = "name")
#KeywordField
private String name;
#OneToOne
#JoinColumn(unique = true)
#Cascade(value = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.SAVE_UPDATE})
#IndexedEmbedded
#IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW)
private EntityB entityB;
}
#Entity
#Table(name = "entityB")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class EntityB {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
#GenericField
private Long id;
#Column(name = "name")
#KeywordField
private String name;
#OneToOne(cascade = {}, fetch = FetchType.EAGER, targetEntity = EntityA.class)
#JoinColumn(name = "id", nullable = false)
#IndexingDependency(reindexOnUpdate = ReindexOnUpdate.DEFAULT)
private EntityA entityA
}
When I first persist EntityA, that being the entity that is indexed, the EntityB is persisted in the elasticsearch index as a child of EntityA. This is ok. The problem appears when I directly edit EntityB and make changes to it, this changes are not propagated to the elasticsearch index. Is something that i am missing?
UPDATE 1
After #yrodiere answers, i made this changes :
#OneToOne
#JoinColumn(unique = true)
#Cascade(value = {CascadeType.MERGE, CascadeType.PERSIST,
CascadeType.SAVE_UPDATE})
#IndexedEmbedded
#AssociationInverseSide(inversePath = #ObjectPath(
#PropertyValue(
propertyName = "entitya" ) ))
private EntityB entityB;
The problem still persist. If i do something like this :
EntityB b = entityBRepository.findById(5051L).get();
b.setProperty("3333");
entityBRepository.save(b);
Regards.
The problem appears when I directly edit EntityB and make changes to it, this changes are not propagated to the elasticsearch index.
You explicitly instructed Hibernate Search to behave exactly that way:
#IndexingDependency(reindexOnUpdate = ReindexOnUpdate.SHALLOW)
private EntityB entityB;
reindexOnUpdate = ReindexOnUpdate.SHALLOW means "reindex EntityA when the entityB property of EntityA changes, but not when a property of EntityB itself (e.g. its name) changes".
See this section of the reference documentation.
I'm guessing you added that to get rid of an exception telling you that Hibernate Search was unable to find the inverse side of the association EntityA.entityB. In your case, it seems you should rather tell Hibernate Search what the inverse side of that association is. Either add a mappedBy to one side of the association (Warning: this will change your DB schema), or use #AssociationInverseSide (see this section of the documentation).

Eager query in a lazy relation?

I have an entity with lazy relations like this:
#Getter
#Entity
#Table(name = "entity")
#SequenceGenerator(name = "seq_entity", sequenceName = "seq_entity", allocationSize = 1)
#DynamicUpdate
public class Entity {
#Id
#Column(name = "id_entity")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_entity")
private Long id;
#Setter
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_relation1")
private Relation1 relation1;
#Setter
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_relation2")
private Relation2 relation2;
// ...
}
When I make a query to load the other relations I have to specify them like:
return jpaQuery()
.select(qEntity)
.distinct()
.from(qEntity)
.innerJoin(qEntity.relation1).fetchJoin()
.leftJoin(qEntity.relation2).fetchJoin()
.fetch();
But I want to load them without specify into left joins and inner joins for one query...
There is a way to load all in eager mode for one query? Is it possible to desactivate the FetchType.LAZY for one query?
I am thinking in something like
return jpaQuery()
.select(qEntity)
.distinct()
.from(qEntity)
.fetchEager();
You can use entity graph for that. It will be something like this:
EntityGraph<Post> entityGraph = entityManager.createEntityGraph(YourEntity.class);
entityGraph.addAttributeNodes("relation1");
entityGraph.addAttributeNodes("relation2");
And in query
TypedQuery<Post> typedQuery = entityManager.createQuery(criteriaQuery);
typedQuery.setHint("javax.persistence.loadgraph", entityGraph);
Post post = typedQuery.getSingleResult();
This can be enclosed with named entity graph (over entity)
#NamedEntityGraph(
name = "entity-with-all-relations",
attributeNodes = {
#NamedAttributeNode("relation1"),
#NamedAttributeNode("relation2"),
},
thus reused many times. To do that, you use EntityManager#getEntityGraph

Hibernate inheritance, duplicate ID's in two different tables

#Entity
#Table(name = "parent");
#Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Parent {
#Id
#SequenceGenerator(name = "ME_SEQ", sequenceName = "ME_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ME_SEQ")
#Column(name = "PARENT_ID", columnDefinition = "NUMBER(38,0)", nullable = false, unique = true)
private Long id;
}
There is also a child entity (seperate table) which has a PK and FK that points to Parent ID.
#Entity
#Table(name = "child")
public class Child extends Parent {
#Id
#Column(name = "PARENT_ID")
private Long id;
}
Even though there is two separated tables, I get an error from Hibernate:
org.hibernate.mapping.UnionSubclass cannot be cast to
org.hibernate.mapping.RootClass
Is it not possible to have ID in the child class, even if it's a different table from the parent?

#ManyToOne not filling the parent id field

I have a many-to-one bidirectionnal relationship between a parent and child entity. The problem is, when i'm persisting the child, the parent_id isn't persisted. The other fields are fine, but parent_id stay at NULL. I'm using Spring Data JPA with Hibernate and mapstruct to convert between entity and dto, if that can help.
The java files are the following :
#Entity
#Table(name = "Parent")
public class ParentEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToMany (fetch = FetchType.LAZY, mappedBy="parent_entity", cascade = { CascadeType.ALL })
private List<Child> children;
}
#Entity
#Table(name = "Child")
public class ChildEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#ManyToOne(optional = true)
#JoinColumn(nullable = true, name = "parent_entity_id", insertable = false, updatable = false)
private Parent parent_entity;
}
I already tried a bunch of answers from SO, but to no avail for now.
Since you're using bidirectional relationship, you are now responsible to set a parent for your child. And remove insertable = false.
As far as I know. You have to add each other in both parent and child. Only adding children to the list does not seem to work.
Try it out, and see if that fixes the problem.

NamedQuery miss places table in OnetoOne relation

i have a problem with named query in my project. I have 2 entities with OneToOne relation.
#Entity
#Table(name = "SL_BRANCH_PARAMS")
public class BranchParams implements Identifiable {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "SL_BRANCH_PARAM_SEQ_GEN")
#SequenceGenerator(name = "SL_BRANCH_PARAM_SEQ_GEN", sequenceName = "SL_BRANCH_PARAM_SEQ")
private Long id;
#JoinColumn(name = "INTEREST_ACCOUNT_ID")
#OneToOne(fetch = FetchType.EAGER)
private AccountDef interestAccount;
}
and second class with named query
#Entity
#Table(name = "SL_ACCOUNT_DEF")
#NamedQueries({
#NamedQuery(name = "AccountDef.getAvaibleInterestAccountsForBranch",
query = "SELECT ad FROM AccountDef ad LEFT JOIN FETCH ad.branchParamsInterest WHERE ad.branchParamsInterest = NULL ORDER BY ad.id ASC"),
})
public class AccountDef implements Identifiable {
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "SL_ACCOUNT_DEF_SEQ_GEN")
#SequenceGenerator(name = "SL_ACCOUNT_DEF_SEQ_GEN", sequenceName = "SL_ACCOUNT_DEF_SEQ")
private Long id;
#OneToOne(fetch = FetchType.EAGER, mappedBy = "interestAccount")
private BranchParams branchParamsInterest;
}
When i execute the named query I get this query to database
select
accountdef0_.ID as ID1_10_0_,
branchpara1_.ID as ID1_13_1_,
branchpara1_.INTEREST_ACCOUNT_ID as INTERES16_13_1_
from
SL_ACCOUNT_DEF accountdef0_
left outer join
SL_BRANCH_PARAMS branchpara1_
on accountdef0_.ID=branchpara1_.INTEREST_ACCOUNT_ID
where
accountdef0_.ID is null //this is incorrect
order by
accountdef0_.ID ASC
which is not correct because it gives me no rows as it checks if the ID in AccountDef is null instead in BranchParams.
The correct query should look like this
select
accountdef0_.ID as ID1_10_0_,
branchpara1_.ID as ID1_13_1_,
branchpara1_.INTEREST_ACCOUNT_ID as INTERES16_13_1_
from
SL_ACCOUNT_DEF accountdef0_
left outer join
SL_BRANCH_PARAMS branchpara1_
on accountdef0_.ID=branchpara1_.INTEREST_ACCOUNT_ID
where
branchpara1_.ID is null //this is correct
order by
accountdef0_.ID ASC
and such query returns the rows i want. And the question from me is, why named query checks null id value for AccountDef instead for BranchParams?
Perhaps something like this?
#NamedQuery(name = "AccountDef.getAvaibleInterestAccountsForBranch",
query = "SELECT ad FROM AccountDef ad LEFT JOIN FETCH ad.branchParamsInterest bp WHERE bp.interestAccount = NULL ORDER BY ad.id ASC")

Categories