Create one to one relationship with join table in hibernate - java

I have a many to one relationship from the class client to estimate.
#OneToMany( mappedBy = "fkIdClientEstimate", cascade = CascadeType.ALL)
private List<Estimate> estimateList = new ArrayList<>();
But is it possible to create a one to one relationship from estimate to client. I tried something like this but it does not enter any values into the database ?
#OneToOne( cascade = CascadeType.ALL)
#JoinTable(
name = "tbl_estimate_client",
joinColumns = #JoinColumn( name="id_estimate"),
inverseJoinColumns = #JoinColumn( name="id_client"))
private Client client ;
I also tried it with private Client client = new clientBut it creates a new client into the database instead.

Related

Hibernate ManyToMany Method threw 'org.hibernate.LazyInitializationException' exception

I have ManyToMany relationships in Hibernate
Project.class
#ManyToMany
#JoinTable(
name = "user_projects",
joinColumns = { #JoinColumn(name = "project_id")},
inverseJoinColumns = { #JoinColumn(name = "user_id")}
)
private Set<User> projectUsers = new HashSet<>();
User.class
#ManyToMany(fetch = FetchType.EAGER,
mappedBy="projectUsers",
cascade = CascadeType.ALL)
private Set<Project> userProjects = new HashSet<>();
And when I get current user thru
#AuthenticationPrincipal User user
I have Method threw 'org.hibernate.LazyInitializationException' exception when user.getUserProjects();
It's because when using #ManyToMany, first all Projects of user are fetched, then all Users of fetched Projects and so on... This cyclic dependency causes the error, because there is eager fetching missing on Project side.
The solution would be to use:
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "user_projects",
joinColumns = { #JoinColumn(name = "project_id")},
inverseJoinColumns = { #JoinColumn(name = "user_id")}
)
private Set<User> projectUsers = new HashSet<>();
Although I do not recommend this solution, because of performance issues (and possible side effects). Better solution would be to have an entity for join table.
Try to use #Transactional maybe can solved it because
the #Transactional annotation on the getFavorites() method indicates that the session will be closed at the end of this method

What is the purpose of CascadeType.MERGE in Many to Many relationships?

Suppose we have a Post class with a tags reference that is a List:like this (Original source):
#ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "post_tag",
joinColumns = #JoinColumn(name = "post_id"),
inverseJoinColumns = #JoinColumn(name = "tag_id")
)
private List<Tag> tags = new ArrayList<>();
Why do we need CascadeType.MERGE? Is this in the event that, for example, we remove tags from the list and then we persist the post, thus we want the result to "Merge" (Unmap the tags from the post in the many to many join table) with the current database state?

JPA Map mapping to join table with 3 columns

I have list that is mapped by a join table. What I need to do is make the combinations of "layouts" and 'views' not unique and also each with an index. What I thought of trying to do is making a Map<Integer, View> and somehow make the join table have a third column 'id'. What would happen is get the views of that layout and populate them with the id from the join table as a key in the map.
Any idea how to do that, or maybe a better idea for what I need?
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(
name = "layout_view",
joinColumns = {#JoinColumn(name = "layout_id", nullable = false)},
inverseJoinColumns = {#JoinColumn(name = "view_id", nullable = false)}
)
private List<View> views;
What I imagine:
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(
name = "layout_view",
joinColumns = {#JoinColumn(name = "layout_id", nullable = false)},
inverseJoinColumns = {#JoinColumn(name = "view_id", nullable = false)}
//some code for third column and populating it as keys
)
private Map<Integer, View> views;
You can already have multiple same views for a layout by using a List, as you're doing.
To preserve (and be able to change) the order, see OrderColumn and the Hibernate documentation about ordered lists​.
The same documentation also describes how to implement your original idea with a map, if you really want that.

Creating OrderColumn for OneToMany list mapping on a join table in Hibernate

I have a productJob table and a quadrat table. Every quadrat can be installed on many productJob and every productJob can have between 1 and 4 quadrats of the same or different kinds! I'm interested to keep the order of quadrat installation on the product jobs. For example first, second, third or forth place! But the following mapping doesn't create the order column on the JoinTable telai_quadrati. What is the problem of my mapping? The orderColumn isn't created in anyway!
#Entity
#Table(name = "telai")
public class ProductJob implements IProductJob, IProductJobProcessing{
#Embedded private QuadratGroup quadrateGroup = new QuadratGroup();
}
#Embeddable
public class QuadratGroup implements Serializable{
#OneToMany(targetEntity = Quadrat.class, cascade = CascadeType.ALL)
#JoinTable(
name = "telai_quadrati",
joinColumns = {#JoinColumn(name = "dbId", table = "telai")},
inverseJoinColumns = {#JoinColumn(name = "id", table = "quadrati")})
//#OrderColumn(name = "order")
#IndexColumn(name = "order")
public List<Quadrat> getQuadratList(){ //return an ordered list of the quadrats with at most 4 elements}
And it is clear that for the quadrats there exists no order so I use set!
#Entity
#Table(name = "quadrati")
public class Quadrat implements IQuadrat, Cloneable, Serializable{
#ManyToMany
#JoinTable(
name = "telai_quadrati",
joinColumns = #JoinColumn(name = "id", table = "quadrati"),
inverseJoinColumns = #JoinColumn(name = "dbId", table = "telai"))
private Set<ProductJob> productJobs;
It works if I use property access inspite of method access! Like this:
#OneToMany(targetEntity = Quadrat.class, cascade = CascadeType.ALL)
//#MapKeyJoinColumn(name="indice" , table = "telai_quadrati")
#JoinTable(
name = "telai_quadrati",
joinColumns = {#JoinColumn(name = "telaio_id", table = "telai")},
inverseJoinColumns = {#JoinColumn(name = "quadrato_id", table = "quadrati")})
#OrderColumn(name = "indice")
private List<Quadrat> quadratList;
But I wonder why it doesn't work with method access that forces me a heavy refactor in my project! :(

ManyToMany remove problem

I have a table: DocumentType:
#ManyToMany(cascade = {CascadeType.REFRESH, CascadeType.MERGE, CascadeType.PERSIST}, fetch = FetchType.LAZY)
#JoinTable(
name = "document_type_property_type",
joinColumns = #JoinColumn(name = "document_type"),
inverseJoinColumns = #JoinColumn(name = "property_type")
)
#Cascade({org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
#ForeignKey(name = "FK_DOCUMENT_TYPE_PROPERTY_TYPE__DOCUMENT_TYPE", inverseName = "FK_DOCUMENT_TYPE_PROPERTY_TYPE__PROPERTY_TYPE")
#Sort(type = SortType.NATURAL)
private SortedSet<PropertyType> propertyTypes = new TreeSet<PropertyType>();
and PropertyType:
#ManyToMany(cascade = {CascadeType.REFRESH, CascadeType.MERGE, CascadeType.PERSIST}, fetch = FetchType.LAZY)
#JoinTable(
name = "document_type_property_type",
joinColumns = #JoinColumn(name = "property_type"),
inverseJoinColumns = #JoinColumn(name = "document_type")
)
#Cascade({org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
#Sort(type = SortType.NATURAL)
protected SortedSet<DocumentType> documentTypes = new TreeSet<DocumentType>();
As you see the bridge table for ManyToMany is: document_type_property_type.
I do not understand why if i remove a property type from a doc type it not only deletes it from bridge table (as i want/expect) but also deletes it from property type itself (which i want to avoid!).
Can you give me a work-around?
Thanks.
Edit: code for deleting a property type - doc type relation:
public void removePropertyType(final PropertyType propertyType) {
super.performDAudit(propertyType);
final DocumentType currentInstance = getInstance();
currentInstance.getPropertyTypes().remove(propertyType);
getEntityManager().persist(propertyType);
FacesMessages.instance().add(StatusMessage.Severity.INFO, "Property Type was succesfully removed from this document type");
}
I notice that you have the cascade type set to DELETE_ORPHAN on both sides of the relationship. I think you may either have to set it on one side or none. I am not sure that DELETE_ORPHAN is relevant in your scenario.
As I understand it, only one side of the relationship actually "owns" the relationship. That is the side that should manage all cascades and so on and the inverse side should do nothing.

Categories