Hibernate: multiple #ManyToMany relations in a single table - java

I have a project where Hibernate is used to manage entities. Multiple #ManyToMany relations can exists between two tables. So basically i have code like this:
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "movies_screenplay_authors",
joinColumns = #JoinColumn(name = "movie_id", nullable = false, updatable = false),
inverseJoinColumns = #JoinColumn(name = "staff_id", nullable = false, updatable = false))
private Set<Staff> screenplayAuthors = Sets.newHashSet();
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "movies_story_authors",
joinColumns = #JoinColumn(name = "movie_id", nullable = false, updatable = false),
inverseJoinColumns = #JoinColumn(name = "staff_id", nullable = false, updatable = false))
private Set<Staff> storyAuthors = Sets.newHashSet();
Now, I would like to store those relations inside a single table, with some additional column describing relation type. So basically, I would like to have something like this (pseudo-code used):
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "movies_staff",
joinColumns = #JoinColumn(name = "movie_id", nullable = false, updatable = false),
inverseJoinColumns = #JoinColumn(name = "staff_id", nullable = false, updatable = false),
joinCriteria = #JoinCriteria(columnName = "staff_type", value = StaffType.SCREENPLAY_AUTHOR, enumType = EnumType.STRING))
private Set<Staff> screenplayAuthors = Sets.newHashSet();
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "movies_staff",
joinColumns = #JoinColumn(name = "movie_id", nullable = false, updatable = false),
inverseJoinColumns = #JoinColumn(name = "staff_id", nullable = false, updatable = false),
joinCriteria = #JoinCriteria(columnName = "staff_type", value = StaffType.STORY_AUTHOR, enumType = EnumType.STRING))
private Set<Staff> storyAuthors = Sets.newHashSet();
Is this even possible, in Hibernate, or anywhere in Java world?

You can add after each #JoinTable annotation something like this:
#Fetch(FetchMode.SUBSELECT)
And its all.

Related

hibernate #joincolumns with insertable true not allowing insert

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

Preventing circular JSON conversions on ManyToMany entities

I am converting JPA entities to JSON for a REST API. Several of the entities have ManyToMany relationships which can cause recursion in the conversion process. I understand how to use #JsonIgnoreProperties to prevent recursion on the ManyToOne relationship, but not ManyToMany. Any guidance appreciated. Here is an example:
#ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST,CascadeType.DETACH})
#JoinTable(name = "insurance_companycodes", joinColumns = {
#JoinColumn(name = "insurance_id", referencedColumnName = "id", nullable = false, updatable = false) }, inverseJoinColumns = {
#JoinColumn(name = "insuranceCompanyCode_id", referencedColumnName = "id", nullable = false, updatable = false) })
private Set<InsuranceCompanyCode> insuranceCompanyCodes = new HashSet<>();

Hibernate ManyToOne relation with multiple JoinColumn is not lazy fetched

I have a following example I want to create a lazy #ManyToOne relation between Car and CarAchievement tables using multiple join columns (example of class below)
#Entity
#Table(name = "CAR")
public class Car implements Serializable {
#Id
#GenericGenerator(name = "SEQ_CAR", strategy = "sequence",
parameters = {
#org.hibernate.annotations.Parameter(
name = "sequence",
value = "SEQ_CAR"
)
}
)
#GeneratedValue(generator = "SEQ_CAR")
#Column(name = "ID")
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#NotFound(action = NotFoundAction.IGNORE)
#JoinColumns({
#JoinColumn(name = "region", referencedColumnName = "region", updatable = false, insertable = false),
#JoinColumn(name = "model", referencedColumnName = "model", updatable = false, insertable = false),
#JoinColumn(name = "year", referencedColumnName = "type", updatable = false, insertable = false),
#JoinColumn(name = "type", referencedColumnName = "year", updatable = false, insertable = false)
})
#JsonIgnore
private CarAchievement carAchievement;
}
This relation works fine but it seems not to be a LazyFetch, every query for a CAR seems to be fetching CarAchievement automatically even when its not specified to fetch this relation
Hibernate version: 4.3.10.Final

mappedBy and joinTable in wrong class

I used seam to generate my entities. But I have a many to many composite table with an employee id and a vehicle id and it generated the hash sets wrong. I want to be able to choose an employee's favorite vehicle in the employee object. However; when I add things to the hashset in the employee object and persist it, it does not add anything to the composite table. The vehicle object has the
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "flower_store_emp_vehicle", schema = "dbo", catalog = "tyler", joinColumns = { #JoinColumn(name = "vehicle_id", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "employee_id", nullable = false, updatable = false) })
and the employee object has the:
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "flowerStoreEmployees")
I am guessing these are backwards, however; I am new to seam and do not how to switch them around without the mappedBy being all wrong. If anyone knows how to help it would be greatly appreciated. Thank you
If you want the employee to be the owner of the association, just switch the annotations:
Employee:
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "flower_store_emp_vehicle",
schema = "dbo",
catalog = "tyler",
inverseJoinColumns = { #JoinColumn(name = "vehicle_id", nullable = false, updatable = false) },
joinColumns = { #JoinColumn(name = "employee_id", nullable = false, updatable = false) })
private Set<Vehicle> vehicles;
Vehicle:
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "vehicles")
private Set<Employee> employees;

HQL: Hibernate query with ManyToMany

I have a question with HQL query and hibernate.
I have a user class and a role class. A user can have many roles. So I have a ManyToMany relatation like this:
In user class:
#ManyToMany(fetch = FetchType.LAZY)
#oinTable(name = "PORTAIL_USERROLE", joinColumns = { #JoinColumn(name = "USERID", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "ROLE", nullable = false, updatable = false) })
public Set<Portailrole> getPortailroles() {
return this.portailroles;
}
In role class:
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "PORTAIL_USERROLE", joinColumns = { #JoinColumn(name = "ROLE", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "USERID", nullable = false, updatable = false) })
public Set<Portailuser> getPortailusers() {
return this.portailusers;
}
This mapping has created a 3rd table (PORTAIL_USERROLE) where relations are stocked.
All work fine like this. When I have a user, I retrieve roles.
But, my question is: in a HQL query, how can I get all users which have a specific role ? Any class represents PORTAIL_USERROLE table so I don't know how to make my HQL query.
This should do it:
from Portailuser u join u.portailroles r where r.name=:roleName
you can use
#WhereJoinTable
Like this:
#JoinTable(name = "OFFICE_USER_POSITION", joinColumns = {
#JoinColumn(name = "user_id", referencedColumnName = "id")}, inverseJoinColumns = {
#JoinColumn(name = "POST_ID", referencedColumnName = "id")})
#WhereJoinTable(clause = "primary_flag='" + YES + "' and del_flag='" + DEL_FLAG_NORMAL + "'")

Categories

Resources