I have 4 entities: workflowEntity, PhaseEntity, RoundEntity and BlockEntity.
The structure is supposed to be following:
Workflow:
Phase:
Round(optional):
Block
or if there are no rounds, since round_id in workflow_binding table is nullable;
Workflow:
Phase:
Block
I need workflowEntity, when bound with Phase, Block or Round entities, to hold the information of those entitites, but those other entites should not contain any information of their "structural children". e.g I request getAllPhases(), then those Phases that get returned, should not contain information of any Blocks nor Rounds, because unless phases are bound within workflow, they are not tied with Blocks nor Rounds in any way. They can only be tied with Blocks and Rounds in bound workflowEntity.
I have tried to use #JoinTable (commented out examples in workflowEntity, PhaseEntity and RoundEntity), but this returned too much data, that wasnt bound to requested workflow.
Basically I need WorkflowEntity to contain fields such as:
private Map<PhaseEntity, Map<RoundEntity, Set<BlockEntity>>> phaseRoundEntityMap;
private Map<PhaseEntity, Set<BlockEntity>> phaseBlockEntityMap;
#Entity
#Data
#Table(name="workflow")
public class WorkflowEntity {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
#Column(name = "id")
private UUID id;
#NotBlank
#Size(min = 1, max = 255)
#Column(name= "name")
private String name;
#Column(name="days")
private Integer days;
/*
#OneToMany(cascade = {CascadeType.DETACH, CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.REMOVE}, fetch = FetchType.EAGER)
#JoinTable(name = "workflow_binding",
joinColumns = {#JoinColumn(name = "workflow_id")},
inverseJoinColumns = {#JoinColumn(name = "workflow_phase_id")})
private Set<PhaseEntity> phases;*/
//I need to map these somehow
private Map<PhaseEntity, Map<RoundEntity, Set<BlockEntity>>> phaseRoundEntityMap;
private Map<PhaseEntity, Set<BlockEntity>> phaseBlockEntityMap;
}
#Entity
#Data
#Table(name="workflow_phase")
#NoDuplicatePhases
public class PhaseEntity {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
#Column(name = "id", updatable = false, nullable = false)
private UUID id;
#NotBlank
#Size(min = 1, max = 255)
private String name;
#Size(max = 1500)
private String description;
private Integer sequenceNumber;
// Phase shouldnt actually contain any information about blocks nor rounds, unless bound with a workflow.
/* Commented out, because includes blocks and rounds not bound to requested workflow
#OneToMany(cascade = {CascadeType.DETACH, CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.REMOVE}, fetch = FetchType.EAGER)
#JoinTable(name = "workflow_binding",
joinColumns = {#JoinColumn(name = "workflow_phase_id")},
inverseJoinColumns = {#JoinColumn(name = "workflow_block_id")})
private Set<BlockEntity> blocks;
#OneToMany(cascade = {CascadeType.DETACH, CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.REMOVE}, fetch = FetchType.EAGER)
#JoinTable(name = "workflow_binding",
joinColumns = {#JoinColumn(name = "workflow_phase_id")},
inverseJoinColumns = {#JoinColumn(name = "workflow_round_id")})
private Set<RoundEntity> rounds;*/
}
#Entity
#Data
#Table(name="workflow_round")
#NoDuplicateRounds
public class RoundEntity {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
#Column(name = "id", updatable = false, nullable = false)
private UUID id;
#NotBlank
#Size(min = 1, max = 255)
private String name;
private Integer sequenceNumber;
/*Commented out, because includes blocks not bound to requested workflow
#OneToMany(cascade = {CascadeType.DETACH, CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.REMOVE}, fetch = FetchType.EAGER)
#JoinTable(name = "workflow_binding",
joinColumns = {#JoinColumn(name = "workflow_round_id", nullable = false, updatable = false)},
inverseJoinColumns = {#JoinColumn(name = "workflow_block_id", nullable = false, updatable = false)})
private Set<BlockEntity> blocks;*/
}
#Entity
#Data
#Table(name = "workflow_block")
public class BlockEntity {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
#Column(name = "id", updatable = false, nullable = false)
private UUID id;
#NotBlank
#Size(min = 1, max = 255)
private String name;
#Size(max = 1500)
private String description;
#OneToMany(cascade = {CascadeType.DETACH, CascadeType.PERSIST, CascadeType.REFRESH, CascadeType.REMOVE, CascadeType.MERGE}, orphanRemoval = true, fetch = FetchType.EAGER)
#JoinTable(name = "workflow_assignment_block",
joinColumns = {#JoinColumn(name = "workflow_block_id", nullable = false, updatable = false)},
inverseJoinColumns = {#JoinColumn(name = "workflow_assignment_id")})
private Set<AssignmentEntity> assignments;
private Integer sequenceNumber;
#Column(name = "due_date_day")
private Integer dueDate;
}
Why not create an entity WorkflowBinding?
#Entity
#Table(name = "workflow_binding")
public class WorkflowBinding {
#EmbeddedId
private WorkflowBindingId id;
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "block_id", insertable = false, updatable = false)
private BlockEntity block;
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "round_id", insertable = false, updatable = false)
private RoundEntity round;
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "phase_id", insertable = false, updatable = false)
private PhaseEntity phase;
#ManyToOne(fetch = LAZY)
#JoinColumn(name = "workflow_id", insertable = false, updatable = false)
private WorkflowEntity workflow;
}
#Embeddable
public class WorkflowBindingId {
private UUID blockId;
private UUID roundId;
private UUID phaseId;
private UUID workflowId;
}
On the inverse side you can then do mappings like this:
public class BlockEntity {
#OneToMany(mappedBy = "block")
private Set<WorkflowBinding> bindings;
....
}
Related
I have a couple of tables with relation as in the image below
I created hibernate data model as follows
#Entity
#Table(name = "SUBJECT")
public class Subject {
#Column(name = "NAME")
private String name;
#Column(name = "ADDRESS")
private String address;
#Column(name = "CLIENT_ID")
private String clientId;
#OneToMany(mappedBy = "subject", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<SSI> SSIs;
// getters and setters
...
}
#Entity
#Table(name = "SUBJECT_IDENTIFIER")
public class SubjectIdentifier {
#Column(name = "VALUE")
private String value;
#Column(name = "AUTHORITY")
private String authority;
#Column(name = "TYPE")
private String type;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "SUBJECT_ID", referencedColumnName = "ID", insertable = true,
updatable = true,
#JoinColumn(name = "CLIENT_ID", referencedColumnName = "CLIENT_ID", insertable =
true, updatable = true)
})
private Subject subject;
// getters and setters
...
}
#Entity
#Table(name = "SSI")
public class SSI {
#ManyToOne
#JoinColumns({
#JoinColumn(name = "SUBJECT_ID", referencedColumnName = "ID", insertable = true,
updatable = true),
#JoinColumn(name = "CLIENT_ID", referencedColumnName = "CLIENT_ID", insertable =
true, updatable = true)
})
private Subject subject;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "SUBJECT_IDENTIFIER_ID", referencedColumnName = "ID", insertable = true,
updatable = true),
#JoinColumn(name = "CLIENT_ID", referencedColumnName = "CLIENT_ID", insertable =
true, updatable = true)
})
private SubjectIdentifier subjectIdentifier;
// getters and setters
...
}
I intend to create the entities as follows
...
Subject s = new Subject();
//.. initialization of s goes here
SubjectIdentifier si = new SubjectIdentifier();
//.. initialization of si goes here
SSI ssi = new SSI();
ssi.setSubject(s);
ssi.setSubjectIdentifier(si);
s.setSSI(ssi);
...
emProvider.get().persist(s);
When I run this, I get following error
org.hibernate.MappingException: Repeated column in mapping for entity: *.SSI column: CLIENT_ID (should be mapped with insert="false" update="false")
If I set insert="false" update="false" for CLIENT_ID, it would error again about mixing of insert & update with other column in the #Joincolumns
If I set insert="false" update="false" for all the #JoinColumns then it will not persist the objects.
How to really handle this kind of entity creation?
That's not so easy. If you want that, you have to introduce another attribute for storing the client id and maintain this denormalization:
#Entity
#Table(name = "SSI")
public class SSI {
#Column(name = "CLIENT_ID")
private String clientId;
#Column(name = "SUBJECT_ID")
private String subjectId;
#Column(name = "SUBJECT_IDENTIFIER_ID")
private String subjectIdentifierId;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "SUBJECT_ID", referencedColumnName = "ID", insertable = false,
updatable = false),
#JoinColumn(name = "CLIENT_ID", referencedColumnName = "CLIENT_ID", insertable =
false, updatable = false)
})
private Subject subject;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "SUBJECT_IDENTIFIER_ID", referencedColumnName = "ID", insertable = false,
updatable = false),
#JoinColumn(name = "CLIENT_ID", referencedColumnName = "CLIENT_ID", insertable =
false, updatable = false)
})
private SubjectIdentifier subjectIdentifier;
// getters and setters
...
}
I have a set of entities user and conference. I have implemented a method in which I assign users to a conference and save it. However, when I save the conferencce the intermediate table attendance_table is not updated.
My database erd diagram example:
My entities:
#Entity
#Table(name = "user_table", schema = "public")
public class User {
#Id
#Column(name = "user_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long user_id;
#Column(name = "name")
private String name;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "email")
private String email;
#Column(name = "confirmed")
private boolean confirmed;
#ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH}, fetch = FetchType.LAZY)
#JoinTable(name = "attendance_table",
joinColumns = {
#JoinColumn(name = "user_id", referencedColumnName = "user_id",
nullable = false, updatable = false)},
inverseJoinColumns = {
#JoinColumn(name = "conference_id", referencedColumnName = "conference_id",
nullable = false, updatable = false)})
private Collection<Conference> conferences = new HashSet<>();
#Entity
#Table(name = "conference_table", schema = "public")
public class Conference {
#Id
#Column(name = "conference_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long conference_id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private User creator ;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#Column(name = "startConference")
private Date startConference;
#Column(name = "endConference")
private Date endConference;
#ManyToMany(mappedBy = "conferences", fetch = FetchType.LAZY)
private Collection<User> students;
Any ideas? If you need any extra info I can update the question. Thanks in advance!
This was a interesting fix. I was messing around with the user and conference classes and found a solution.
I had to swap the implementations of #ManyToMany of both classes for it to work.
My User class now looks like:
#Entity
#Table(name = "user_table", schema = "public")
public class User {
#Id
#Column(name = "user_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long user_id;
#Column(name = "name")
private String name;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "email")
private String email;
#Column(name = "confirmed")
private boolean confirmed;
#ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH}, fetch = FetchType.EAGER)
#JoinTable(
name = "user_role_table",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id", referencedColumnName = "role_id"))
private Collection<Role> roles = new HashSet<>();
#ManyToMany(mappedBy = "students", fetch = FetchType.LAZY)
private Collection<Conference> conferences;
And my conference class:
#Entity
#Table(name = "conference_table", schema = "public")
public class Conference {
#Id
#Column(name = "conference_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long conference_id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private User creator ;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#Column(name = "startConference")
private Date startConference;
#Column(name = "endConference")
private Date endConference;
#ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH}, fetch = FetchType.LAZY)
#JoinTable(name = "attendance_table",
joinColumns = {
#JoinColumn(name = "conference_id", referencedColumnName = "conference_id",
nullable = false, updatable = false)},
inverseJoinColumns = {
#JoinColumn(name = "user_id", referencedColumnName = "user_id",
nullable = false, updatable = false)})
private Collection<User> students = new HashSet<>();
Still not exactly sure why it works like this and not the other way around. If anyone knows please explain!
Need criteria join query for a composite primary key.
Entities:
ArtWork
#Entity
#Table(name = "artwork")
public class ArtWork implements io.malevich.web.entity.Entity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Id
#Column(name = "language", columnDefinition = "CHAR(2)")
private String language;
#Column(name = "art_name", nullable = false)
private String artName;
#Column(name = "creation_date", nullable = false)
private Date creationDate;
#Column(name = "edition_flag", nullable = false, columnDefinition = "tinyint(1)")
private boolean editionFlag;
#Column(name = "replica_flag", nullable = false, columnDefinition = "tinyint(1)")
private boolean replicaFlag;
#Column(name = "number_of_editions")
private Long numberOfEditions;
#Column(name = "original_id")
private Long originalId;
#ManyToOne
#JoinColumns({
#JoinColumn(
name = "category_id",
referencedColumnName = "id", insertable = false, updatable = false),
#JoinColumn(
name = "language",
referencedColumnName = "language", insertable = false, updatable = false)
})
private Category category;
#ManyToOne
#JoinColumns({
#JoinColumn(
name = "gallery_id",
referencedColumnName = "id", insertable = false, updatable = false),
#JoinColumn(
name = "language",
referencedColumnName = "language", insertable = false, updatable = false)
})
private Gallery gallery;
#ManyToOne
private Specialization specialization;
#ManyToOne
#JoinColumns({
#JoinColumn(
name = "author_id",
referencedColumnName = "id", insertable = false, updatable = false),
#JoinColumn(
name = "language",
referencedColumnName = "language", insertable = false, updatable = false)
})
private Author author;
#Column
private String description;
#Column
private Double price;
//getter setter
}
User:
#javax.persistence.Entity
#Table(name = "user")
public class User implements Entity, UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true, length = 255, nullable = false)
private String name;
#Column(length = 255, nullable = false)
private String password;
#ElementCollection(fetch = FetchType.EAGER)
private Set<Role> roles = new HashSet<>();
#Column(name = "user_type_id")
private Long userTypeId;
#ManyToOne
#JoinColumn(name = "person_id", referencedColumnName = "id")
private Person person;
#ManyToOne
#JoinColumn(name = "organization_id", referencedColumnName = "id")
private Organization organization;
#ManyToOne
#JoinColumn(name = "file_id", referencedColumnName = "id")
private File file;
#Column(name = "activity_flag")
private boolean activityFlag;
//gettter and setter
}
Account States
#javax.persistence.Entity
#Table(name = "account_states")
public class AccountStates implements Entity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(insertable = false, updatable = false)
private String language;
#ManyToOne
#JoinColumns({ #JoinColumn(name = "artwork_id", referencedColumnName = "id"),
#JoinColumn(name = "language", referencedColumnName = "language") })
private ArtWork artwork;
#ManyToOne
#JoinColumn(name = "art_owner_id", referencedColumnName = "id")
private User artOwner;
#Column(name = "quantity")
private Long quantity;
#Temporal(TemporalType.DATE)
#Column(name = "buy_date")
private Date buyDate;
}
Account State Dao:
public class JpaAccountStatesDao extends JpaDao
implements AccountStatesDao {
public JpaAccountStatesDao() {
super(AccountStates.class);
}
#Override
public AccountStates find(Long artOwnerId, Long artworkId, String language) {
final CriteriaBuilder builder = this.getEntityManager().getCriteriaBuilder();
final CriteriaQuery<AccountStates> criteriaQuery = builder.createQuery(AccountStates.class);
Root<AccountStates> root = criteriaQuery.from(AccountStates.class);
Predicate p1 = builder.and(builder.equal(root.get("artwork"), artworkId),
builder.equal(root.get("artwork"), language), builder.equal(root.get("artOwner"), artOwnerId));
criteriaQuery.where(p1);
TypedQuery<AccountStates> typedQuery = this.getEntityManager().createQuery(criteriaQuery);
return typedQuery.getSingleResult();
}
}
I want to find Account States where artOwner id = 1 and language = en and artwork id = 1.
Can anyone suggest proper query for the same?
I found a solution for the same, I tried to pass a whole object instead of object id.
So final query is:
#Override
public AccountStates find(User artOwner, Artwork artwork) {
final CriteriaBuilder builder = this.getEntityManager().getCriteriaBuilder();
final CriteriaQuery<AccountStates> criteriaQuery = builder.createQuery(AccountStates.class);
Root<AccountStates> root = criteriaQuery.from(AccountStates.class);
Predicate p1 = builder.and(builder.equal(root.get("artwork"), artwork),
builder.equal(root.get("artOwner"), artOwner));
criteriaQuery.where(p1);
TypedQuery<AccountStates> typedQuery = this.getEntityManager().createQuery(criteriaQuery);
return typedQuery.getSingleResult();
}
}
Now, It works successfully... thanks
I'm trying do maintain a code that was developed when I was busy doing other parts of the system and am taking a beat from some entities related to each other.
The scenario is this:
EntityX has one or more EntityA;
EntityA has one or more EntityB;
EntityB has one or more EntityC;
EntityC has one or more EntityD;
My Entities classes, are:
public class EntityX {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "id", unique = true, insertable = true)
private String id;
#OneToMay(fetch = FetchType.EAGER)
#Fetch(FetchMode.SELECT)
#JoinTable(name = "joinTableX_A",
joinColumns = {#JoinColumn(name = "idX", referencedColumn= "id" ) },
inverseJoinColumns = { #JoinColumn(name = "idA", referencedColumn = "id") })
#Cascade(CascadeType.ALL)
private List<A> aList;
// getters and setters
public class EntityA {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "id", unique = true, insertable = true)
private String id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColun(name = "idX")
private X x;
#OneToMay(fetch = FetchType.EAGER)
#Fetch(FetchMode.SELECT)
#JoinTable(name = "joinTableA_B",
joinColumns = {#JoinColumn(name = "idA", referencedColumn= "id" ) },
inverseJoinColumns = { #JoinColumn(name = "idB", referencedColumn = "id") })
#Cascade(CascadeType.ALL)
private List<B> bList;
// getters and setters
public class EntityB {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "id", unique = true, insertable = true)
private String id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColun(name = "idA")
private A a;
#OneToMay(fetch = FetchType.EAGER)
#Fetch(FetchMode.SELECT)
#JoinTable(name = "joinTableB_C",
joinColumns = {#JoinColumn(name = "idB", referencedColumn= "id" ) },
inverseJoinColumns = { #JoinColumn(name = "idC", referencedColumn = "id") })
#Cascade(CascadeType.ALL)
private List<C> cList;
// getters and setters
public class EntityC {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "id", unique = true, insertable = true)
private String id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColun(name = "idB")
private B b;
#OneToMay(fetch = FetchType.EAGER)
#Fetch(FetchMode.SELECT)
#JoinTable(name = "joinTableC_D",
joinColumns = {#JoinColumn(name = "idC", referencedColumn= "id" ) },
inverseJoinColumns = { #JoinColumn(name = "idD", referencedColumn = "id") })
#Cascade(CascadeType.ALL)
private List<D> dList;
// getters and setters
What I am trying to do is:
When x is deleted, all children a, b, c and d are deleted;
When a is deleted, all children b, c and d are deleted but x is not;
When b is deleted, all children c and d are delete, but x and a are not;
When c is deleted, all children d are deleted, but x, a and b are not.
What am I doing wrong here and how can I get this scenario working?
Try defining your relationships like this, using JPA annotations, you'll even make your code simpler by using the following method:
public class EntityX {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "id", unique = true, insertable = true)
private String id;
#OneToMay(mappedBy = "x", cascade = CascadeType.ALL)
private List<A> aList;
// getters and setters
}
public class EntityA {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "id", unique = true, insertable = true)
private String id;
#ManyToOne
#JoinColumn(name = "idX")
private X x;
//and so on
// getters and setters
}
I think its a better Idea to let JPA handle your join column names, unless you have a restriction
There is part of SQL i want to realize in my Custom JPA repository
SELECT * FROM users u
JOIN skills_user sku on sku.user_id = u.id
JOIN specs_user spu on spu.user_id = u.id
GROUP BY u.id
HAVING ANY(sku.dictionary_id in (15,20) or spu.dictionary_id in (15,20))
ORDER BY u.id
I tried this:
//Other predicates
if (filterQuery.getSkills() != null && !filterQuery.getSkills().isEmpty()) {
String[] tmp = filterQuery.getSkills().replaceAll(" ", "").split(",");
List<Integer> ids = new ArrayList<>();
for (String s : tmp) {
ids.add(Integer.parseInt(s));
}
List<Predicate> tmpPredicates = new ArrayList<>();
Join<User, Dictionary> skillJoin = root.join("skillList");
Join<User, Dictionary> specsJoin = root.join("specsList");
for (Integer id : ids) {
tmpPredicates.add(builder.or(builder.equal(skillJoin.get("id"), id), builder.equal(specsJoin.get("id"), id)));
}
predicates.add(builder.and(tmpPredicates.toArray(new Predicate[tmpPredicates.size()])));
}
//Other predicates
But it isn't work correctly.
How can i realise this correctly in JPA custom repository?
there is code of User and Dictionary classes:
#Entity
#SequenceGenerator(name = "user_gen", sequenceName = "users_seq")
#Table(name = "users")
public class User {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_gen")
private Long id;
#Column(name = "login")
private String login;
#Column(name = "password")
private String password;
#Column(name = "name")
private String name;
#Column(name = "surname")
private String surname;
#Column(name = "middlename")
private String middlename;
#Column(name = "academic_group")
private String academicGroup;
#Column(name = "entrance_year")
private int entranceYear;
#Column(name = "avatar_URL")
private String avatarURL;
#Column(name = "salt")
private String salt;
#Enumerated(EnumType.ORDINAL)
#Column(name = "user_group")
private UserGroup group;
#JsonIgnore
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "SocialRole_User", joinColumns = {
#JoinColumn(name = "user_id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "socialRole_id",
nullable = false, updatable = false) })
private List<SocialRole> socialRoleList;
#JsonIgnore
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "specs_user", joinColumns = {
#JoinColumn(name = "user_id", nullable = false, updatable = true)},
inverseJoinColumns = {#JoinColumn(name = "dictionary_id",
nullable = false, updatable = true)})
private List<Dictionary> specsList;
#JsonIgnore
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "skills_user", joinColumns = {
#JoinColumn(name = "user_id", nullable = false, updatable = true)},
inverseJoinColumns = {#JoinColumn(name = "dictionary_id",
nullable = false, updatable = true)})
private List<Dictionary> skillList;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Contacts> contactsList;
//Getters and setters
}
Dictionary:
#Entity
#SequenceGenerator(name = "dictionary_gen", sequenceName = "dictionary_seq")
#Table(name = "dictionary")
public class Dictionary {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "dictionary_gen")
private Long id;
#Column(name = "dic_name")
private String name;
#Enumerated(EnumType.STRING)
#Column(name = "dic_type")
private DictionaryType type;
// Getters and Setters
}
Have you tried writing the query using JPQL?
SELECT a FROM User a
INNER JOIN a.specsList b
INNER JOIN a.skillList c
GROUP BY a.id
HAVING ANY(b.id in (15,20) OR c.id in (15,20))
ORDER BY a.id;
This JPQL should work the same as your plain SQL.