JPA #ManyToMany ordering failure using #OrderBy - java

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.

Related

Get ElementCollection with native query

I have this entity that i need to join with another unrelated entity, this is why I am using a native query.
#Entity
#Table(name = "surveillance_questionnaires")
#Setter #Getter
public class SurveillanceQuestionnaire {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "surveillance_questionnaires_sequence")
#SequenceGenerator(name = "surveillance_questionnaires_sequence", allocationSize = 5)
private Integer id;
#ElementCollection
#Fetch(FetchMode.JOIN)
#CollectionTable(name = "surveillance_questionnaires_years",
joinColumns = #JoinColumn(name = "id", referencedColumnName = "id"))
#Column(name = "year")
private List<String> years;
...
}
Is there any way to fetch the SurveillanceQuestionnaire entity with its ElementCollection (years) using native query?

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).

Ignore #Formula in one case

I have simple entity with field countUsing which specify count used in other table. It is subquery with annotation Formula.
And i would like in one case ignore execute query in formula but others subquery must invoke.
My entity:
#Entity
#Table(name = "roles")
public class Role {
#Id
#GeneratedValue(generator = "roles_id_seq", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "roles_id_seq", sequenceName = "roles_id_seq", allocationSize = 1)
#Column(name = "id")
private Long id;
#Column(name = "\"NAME\"")
private String name;
#Convert(converter = LocalDateTimeAttributeConverter.class)
private LocalDateTime insertDate;
#Convert(converter = LocalDateTimeAttributeConverter.class)
private LocalDateTime updateDate;
#Formula("(SELECT COUNT(*) FROM user_roles us WHERE us.id_role = id)")
private Integer countUsing;
}
How can i achive the target, i think about flag in any annotation for field countUsing.
Annotation Formula has got only value property.
I understand that you want use FetchType.LAZY on this attribute.
Therefore, you can`t use LAZY directly in a #Formula attribute in your class.
The solution for this is create an wrapper Class, with a oneToOne relationship to your class that`s contain your formula attribute, like this:
#Entity
#Table(name = "roles")
public class Role{
... /*other attributes*/
#OneToOne(fetch = FetchType.LAZY, mappedBy = "role")
private RoleCounting roleCouting;
}
#Entity
#Table(name = "roles")
public class RoleCounting{
#Id
#Column(name="id", insertable = false, updatable = false)
private Long id;
#OneToOne(fetch = FetchType.LAZY)
#MapsId
#JoinColumn(name = "id", insertable = false, updatable = false)
private Role role;
#Formula("(SELECT COUNT(*) FROM user_roles us WHERE us.id_role = id)")
private Integer countUsing;
}
That way, the subquery will only be executed when you invoke:
role.getRoleCounting().getCountUsing();

Hibernate - Populate sub entity on insert

Ive added 2 hibernate model objects
First table
#Entity
#Table(name = "ACTIVITIES")
public class ActivityMO extends ModelBase {
#Column(name = "CA_ID", nullable = false, insertable = true,updatable = true, length = 22, precision = 0)
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "G1")
#SequenceGenerator(name = "G1", sequenceName = "CSM_ACTIVITIES_SEQ")
private Long id;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "activityId", cascade = {CascadeType.ALL})
#Fetch(FetchMode.JOIN)
List<ActivitiesProductsMO> relatedProducts;
...getters / setters
}
The other table is
#Entity
#Table(name = "ACTIVITIES_PRODUCTS")
public class ActivitiesProductsMO {
#Column(name = "CAP_ID")
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "G1")
#SequenceGenerator(name = "G1", sequenceName = "ACTIVITIES_PRODUCTS_SEQ")
private Long id;
#Column(name = "CAP_ACTIVITY_ID")
private Long activityId;
#Column(name = "CAP_PRODUCT_ID")
private Long productId;
...getters/setters
}
The point is to populate each db record for ActivitiesProductsMO.activityId with ActivityMO.id value
I.e.
If I create an activity record with id = 555
I'll get another activity_product record with activityId of 555
How can i get this to work?
Thank you!
Instead of manually trying to map the entitiy relations with long values you should use a bidirectional OneToMany relationship from ActivityMO to ActivitiesProductsMO
change ActivitiesProductsMO to:
#Entity
#Table(name = "ACTIVITIES_PRODUCTS")
public class ActivitiesProductsMO {
// cut unimportant code ...
#ManyToOne
#JoinColumn(name = "CAP_ACTIVITY_ID")
private ActivityMO activityId;
// cut unimportant code ...
}
If you then were to persist an ActivityMO that already has ActivitiesProductsMO entries in its relatedProducts List, the Cascade type should actually take care and create those products while filling out the CAP_ACTIVITY_ID database field with the right value.
Another Possible Solution:
Use a Unidirectional OneToMany:
#Entity
#Table(name = "ACTIVITIES")
public class ActivityMO extends ModelBase {
#OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
#Fetch(FetchMode.JOIN)
#JoinColumn(name = "CAP_ACTIVITY_ID")
List<ActivitiesProductsMO> relatedProducts;
}
And remove the
private Long activityId;
from your ActivitiesProductsMO class.
This should both lead to identical database structure. But in the second case you would no longer have the "backlink" inside java from ActivitiesProductsMO to ActivityMO

Java Persistence Query Language JOIN

I have two tables :
A(bigint id, ...)
B(bigint id, varchar name, bigint id_A)
and now I want get all rows from A which exists in B (and those rows in B have name eg Andy)
Plase help me create dynamic query
class A
#Entity
#Table(name = "A", schema = "mySchema")
#Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
public class A{
#Id
private Long id;
}
class B
#Entity
#Table(name = "B",
schema = "mySchema",
uniqueConstraints = { #UniqueConstraint(columnNames = {
"some_id", "id_A" }) })
public class B{
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "Seq")
#SequenceGenerator(name = "Seq", sequenceName = "mySchema.mySeq")
private Long id;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_A", nullable = false)
private A a;
#Column(name = "id_A", updatable = false, insertable = false)
private Long IdA;
}
There are several weird parts. e.g. this:
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_A", nullable = false)
private A a;
#Column(name = "id_A", updatable = false, insertable = false)
private Long IdA;
With the #JoinColumn annotation you are telling the JPA provider that it should use the specified column for internal mapping, but with the IdA field, you are trying to manage the column yourself. Which is it going to be?

Categories