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.
Related
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.
I've made some research but without any specific answer.
I know how #JsonView... #JsonIgnore works... but my point here is about back end, the point of view from there. I'm working on spring boot and by default OSIV is enabled, so as far as I know, if I'm not wrong, if I make a call in database on an #Entity that has #ManyToMany association it will eagerly fetch everything.
Till there I have no issues, the problem is that the associated Collection also has Collections... And some services need to fetch them and others don't... Then I keep getting LazyInitializationException.
#Entity
#EntityListeners(AuditingEntityListener.class)
#Inheritance(strategy = InheritanceType.JOINED)
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(nullable = false, updatable = false)
private int id;
private String categoryTitle;
private String categoryDescription;
#ManyToMany
#JoinTable(
name = "Category_Parent",
joinColumns = #JoinColumn(name = "id_category", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "id_category_parent")
)
private Set<Category> parentCategory;
#ManyToMany
#JoinTable(
name = "Category_Parent",
joinColumns = #JoinColumn(name = "id_category_parent", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "id_category")
)
private Set<Category> subCategory;
Then to prevent that error I used #Query like this
#Repository
public interface CategoryRepository extends JpaRepository<Category, Integer> {
#Query("from Category c left join fetch c.subCategory left join fetch c.parentCategory")
List<Category> getAllCategories();
}
Now I'm able to fetch it lazly... I used that #Query way because it is the only one I know to fetch the associated Collections... I heared about EntityGraph and Hibernate.initialize() but have no knowledge on how to proceed (would appreciate some link).
So, then I have Json exception because the json response is infinite. How can I avoid this new issue? Using DTO?
I appreciate.
------ EDIT ------
I've used #JsonView on the properties that I want to send as response, however if I use #JsonView over subCategory only, it works, but if I use on parentCategory I got the infinite loop once again... Can't solve it.
You can add fetch = FetchType.LAZY to your #ManyToMany or #OneToMany annotation like this: #ManyToMany(fetch = FetchType.LAZY). More instruction is at https://www.baeldung.com/hibernate-lazy-eager-loading
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
Issue:
Records are deleting automatically from sub entity without firing any save/update statement. Need to prevent that deletion.
Below is entity:
#Entity
#Table(name="siteuser")
public class User implements UserDetails {
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "siteuser_subcategory",
joinColumns = {#JoinColumn(name = "userId") },
inverseJoinColumns = { #JoinColumn(name = "subCategoryId") })
#JsonIgnore
private List<SubCategory> subcategoryList = new ArrayList<SubCategory>();
}
Here in cascade I tried all possible options DETACH,MERGE,PERSIST,REFRESH,REMOVE but no solution.
Also there is no any physical class entity for table 'siteuser_subcategory'. That table managed by only this above code.
I tried many ways to solve this issue as explained in this link
Why does Hibernate try to delete when I try to update/insert?
Please guide for better solutions or anyway by try it.
Thank you in advance.
I am currently using Hibernate in a project and I am having trouble setting up a Many to Many relationship. I think my issue is related to the Cascade types.
The scenario is we have an advert and each advert can have many tags but each tag can be related to many adverts. The ManyToMany annotation of the advert entity is:
#ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
#JoinTable(name = "adMediaAdvertiserTag",
joinColumns = { #JoinColumn(name = "adMediaId") },
inverseJoinColumns = { #JoinColumn(name = "advertiserTagId") })
And the ManyToMany mapping on the tag entity is:
#ManyToMany(mappedBy = "advertiserTags", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
I am seeing two different errors depending on the configuration of the cascade types and if the tag already exists in the database.
If the cascade type on the advert doesn't include PERSIST and the tag doesn't already exist then we get this exception:
TransientObjectException: object references an unsaved transient instance
And if the cascade type on the advert does include PERSIST and the tag does already exist we get:
PersistentObjectException: detached entity passed to persist
The only way I can get this working is not have PERSIST as a cascade type but loop through each tag and save them to the session.
Is this the correct approach? Is there a way that hibernate could automatically handle this for me?
Let me know if this isn't clear or you need any more information.
UPDATE
I am saving the objects using a service that uses the save method the CrudRepository object of the springframework. There is a lot of code so I can't really post it all.
I am currently not calling any merge or persist method for any object I am trying to save. I was under the impression Hibernate would handle that sort of thing for me.
Can you please add the code you are using to persist your Advert and Tag objects. I tested with the following code (which I believe similar to yours) and it works:
User user = new User();
Role role = new Role();
role.setId("TEST_ROLE");
user.getRoles().add(role);
entityManager.persist(user);
User user2 = new User();
user2.getRoles().add(role);
entityManager.persist(user2);
System.out.println(user2.getId());
in User I have:
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
#JoinTable(name = "user_roles",
joinColumns = {#JoinColumn(name = "user_id", nullable = false, updatable = true)},
inverseJoinColumns = {#JoinColumn(name = "role_id", nullable = false, updatable = true)})
protected List<Role> roles = new ArrayList<>();
and in Role I have:
#ManyToMany(mappedBy="roles")
protected List<User> users;