How can i get value from ManyToMany table? - java

I have two classes: Child and Guardian
in Guardian class i have that field:
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "guardian_child", schema = "schema",
joinColumns = #JoinColumn(name = "guardianid"),
inverseJoinColumns = #JoinColumn(name = "childid"))
private List<Child> children = new ArrayList<>();
I have table guardian_child in my Postgres. And now i need to get all children by id of guardian? Need i create special entity and repository for this table? Or how can i do it?

You can get data using JPQL query like this: #Query(SELECT g FROM Guardian JOIN g.children c)... if it doesn't work let me know once again

Related

How to get only ids in #ManyToMany mapping, without referencing the whole object?

I am following the tutorial from baeldung:
https://www.baeldung.com/jpa-many-to-many
The first example is what I need:
The example shows how to add relationship in User class:
#ManyToMany
#JoinTable(
name = "course_like",
joinColumns = #JoinColumn(name = "student_id"),
inverseJoinColumns = #JoinColumn(name = "course_id"))
Set<Course> likedCourses;
The difference in my case is that I do not need to access the whole object when getting the data.
I only need to return the set of Ids.
1.) I have tried the option with #ElementCollection:
#ManyToMany
#JoinTable(
name = "course_like",
joinColumns = #JoinColumn(name = "student_id"),
inverseJoinColumns = #JoinColumn(name = "course_id"))
Set<Course> likedCourses;
#ElementCollection
#CollectionTable(
name = "course_like",
joinColumns = #JoinColumn(name = "student_id"))
Set<Long> likedCourses;
2.) Also, returning the whole object, iterating and storing ids in,
and
3.) There is a third option with #Transient and #PostLoad
public Set<Course> likedCourses;
#Transient
public Set<Long> courseIds;
#PostLoad
private void postLoad() {
courseIds = likedCourses.stream().map(Course::getId).collect(Collectors.toSet());
}
I am looking for the most optimized way, it seems to me option #3 is not good since it could call #Postload potentially more than once.
How would you go about this? Thank you!
You can do it with the following JPQL query:
SELECT c.id
FROM Student s JOIN s.likedCourses c
WHERE s.id = :id
However, I see that Hibernate generates an extra join with the courses table which is unfortunate. If you have problems with that, you can use a native SQL query as #TimBiegeleisen suggested.

Envers not auditing a revision for #ManytoMany+#JoinTable relationship

I have a property that is in Class A as following:
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "tblTestLabelExclude", joinColumns = #JoinColumn(name = "TestId"), inverseJoinColumns = #JoinColumn(name = "LabelId"))
#LazyCollection(LazyCollectionOption.FALSE)
#AuditJoinTable(name="tblB_AUD")
private List<ClassB> someList = new ArrayList<ClassB>();
I have also set #Audited annotation in the appropriate fields in Class B which I want to audit. I have a table also created with the appropriate column names that envers generates. However, it's still not auditing this field. It's auditing other fields that cascade to other entities and they are being audited fine.
Has anyone encountered this or maybe I'm doing something wrong?
Thanks.

merge in jpa many-to-many with extra column in join table

I have a many-to-many relationship with three tables and entities adn the join table contains additional column. On both sides of the relationship I have set cascadeType.All
When I add new objects to owner side the merge method works fine but when I remove a child object from the owner and merge it, the corresponding rows in the join table will not be removed and I will have duplicate rows in there.
owner entity
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "definitionType")
private List<DefinitionProperty> definitionProperties = new ArrayList<DefinitionProperty>();
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "property")
private List<DefinitionProperty> definitionProperties= new ArrayList<DefinitionProperty>();
mapping entity
#Id
#JoinColumn(name = "dtid", referencedColumnName = "id")
#ManyToOne(optional = false)
private DefinitionType definitionType;
#Id
#JoinColumn(name = "prid", referencedColumnName = "id")
#ManyToOne(optional = false)
private Property property;
I am not calling remove method of my entity manager at all and I am expecting the cascading to remove the unwanted rows automatically. Is that possible? what should I do to in order to remove those rows?
I can add my code here if it help
It just needed orphanRemoval=true on the owner side.

JPA Shared Entity mapping

I have a scenario where I have a Object called Page, and another object called Tag, relationship between these two is Page has Tags(many to many), but the same Tags can also shared with Product, here also the relationship is same Product has Tags (many to many).
In normal scenario I will create a type column in Tag where type may be Enum value (product, page) and use query like SELECT * from Tags where parent_id = page_id and type = page.
How to do this in JPA (how to create this relationship and how to query data)
I think you should create two tables of associations. One to associate Pages with tags, one to associate Products with tags. The code:
#Entity
#Table(name = "page")
class Page {
....
#OneToMany
#JoinTable(name = "jnd_pages_tags", joinColumns = #JoinColumn(name = "page_fk"),
inverseJoinColumns = #JoinColumn(name = "tag_fk"))
private Set<Tag> tags;
}
#Entity
#Table(name = "page")
class Product {
....
#OneToMany
#JoinTable(name = "jnd_products_tags", joinColumns = #JoinColumn(name = "products_fk"),
inverseJoinColumns = #JoinColumn(name = "tag_fk"))
private Set<Tag> tags;
}
#Entity
#Table(name = "tags")
class Tag {
.....
}
to select corresponding tags for page, use
SELECT p.t FROM Page p WHERE p.id = :id
to select corresponding tags for product, use
SELECT p.t FROM Product p WHERE p.id = :id

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