ManyToMany mapping issue in Spring Boot - java

I'm trying to do a many-to-many mapping between 2 tables users and products. I wrote their entities and repositories but still the application is giving error. Please help me out if you can, thanks in advance.
Error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: com.poc.joins.entities.User.users in com.poc.joins.entities.Product.users
The code snippets are
User
package com.poc.joins.entities;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table(name = "users")
public class User {
#Id
private String username;
private String password;
#ManyToMany(cascade = CascadeType.MERGE)
#JoinTable(name = "users_products",
joinColumns = {#JoinColumn(name = "username")},
inverseJoinColumns = {#JoinColumn(name = "id")})
private Set<Product> products = new HashSet<>();
}
// Getter, setters, constructors are not shown here
Product
package com.poc.joins.entities;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table(name = "products")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String p_name;
private Integer quantity;
private Float price;
private Float total;
#ManyToMany(mappedBy = "users")
private Set<User> users = new HashSet< >();
}
// Getter, setters, constructors are not shown here

In the owned entity (Product), you pass in the field that owns the relationship (in the User entity):
#ManyToMany(mappedBy = "products")
private Set<User> users = new HashSet< >();
Originally you told the Persistence provider to look for the field called users in the User entity which would hold all the information about the relationship (#JoinTable etc.)

Related

#ManyToMany values are always null

I have this POJO class:
package com.weather.weather.entity;
import jakarta.persistence.*;import lombok.Data;
import lombok.NoArgsConstructor;import org.hibernate.annotations.Proxy;import org.springframework.transaction.annotation.Transactional;
import java.util.List;import java.util.Set;
#Entity#Table(name = "users")#Data#NoArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "collaborator",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id")
)
private Set<Role> roles;
}
Also Role class:
package com.weather.weather.entity;
import jakarta.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Proxy;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Set;
#Entity
#Table(name = "roles")
#Data
#NoArgsConstructor
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// #OneToMany(mappedBy = "role")
// private List<User> users;
#ManyToMany(mappedBy = "roles")
private Set<User> users;
}
But always getRoles() are null.
I have tried changing data to #OneToOne, #ManyToOne, #OneToMany.But its always null.At some point, when i was doing #ManyToOne way, i have got this exception:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.weather.weather.entity.Role.users: could not initialize proxy - no Session
And i found to ways to fix that. I`ve tried putting fetch property, #Proxy(lazy=false), and many many others. Nothing helped
Your annotation #ManyToMany imported from jakarta.persistence.
You should import from javax.persistence.* and you can remove proxy annotation and Lazy fetchType

Use of #OneToMany or #ManyToMany targeting an unmapped class but imports seem good

Here are my entities:
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue
#Column(name = "user_uuid")
private UUID id;
#Column(nullable = false, unique = true)
private String username;
private String password;
}
The User table is used by Spring Security to check the logged in user.
#Entity
#Table(name = "seller")
public class Seller {
#Id
#GeneratedValue
#Column(name = "seller_uuid")
private UUID id;
#ManyToMany
#JoinTable(
name = "seller_user",
joinColumns = #JoinColumn(name = "seller_uuid"),
inverseJoinColumns = #JoinColumn(name = "users_uuid"))
private Set<User> users;
}
But here is the error I get at launch:
Use of #OneToMany or #ManyToMany targeting an unmapped class: seller.modele.entity.Seller.users[user.model.entity.User]
I checked, I use the correct imports (Seller/User and javax.persistence.*)
I guess that your (Spring?) application does not scan the user.model.entity package or you didn't list the fully qualified name of the class in your persistence.xml. In case of Spring, you will have to use e.g. #EntityScan("*") or #EntityScan({"seller.modele.entity.*", "user.model.entity.*"}) or if you don't use that, you will probably have to add <class>user.model.entity.User</class> to your persistence.xml along where your other classes are listed.

How to fix " Error creating bean with name 'entityManagerFactory' defined in class path resource"

I'm just learning spring and I have a problem in the relationship of databases ended with error:
"org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'entityManagerFactory' defined in class path
resource
[org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]:
Invocation of init method failed; nested exception is
org.hibernate.AnnotationException: Unknown mappedBy in:
Varqina.WebReptile.models.entity.UserEntity.userPropertiesEntity,
referenced property unknown:
Varqina.WebReptile.models.entity.UserPropertiesEntity.user"
UserProperies:
import lombok.Data;
import javax.persistence.*;
import java.time.LocalDateTime;
#Table(name = "user")
#Data
#Entity
public class UserEntity {
public enum AccountStatus{
ACTIVE, PREMIUM, NOT_ACTIVE;
}
#Id #GeneratedValue private Integer id;
private String nickname;
private String password;
private #Column(name = "creation_time") LocalDateTime creationTime;
#Enumerated(EnumType.STRING)
private AccountStatus status;
private String email;
#OneToOne(mappedBy = "user",fetch = FetchType.LAZY,cascade = {})
private UserPropertiesEntity userPropertiesEntity;
}
UserPropertiesEntity:
import lombok.Data;
import javax.persistence.*;
#Data
#Entity
#Table(name = "user_properties")
public class UserPropertiesEntity {
private #Id #GeneratedValue Integer id;
private String city;
private String nation;
private #Column(name = "birth_day") String birthDay;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private UserEntity nickname;
The mappedBy attribute in the #OneToOne relationship must correspond to the attribute name in the destination Entity.
So it should be "nickname" not "user"
#OneToOne(mappedBy = "nickname",fetch = FetchType.LAZY,cascade = {})
private UserPropertiesEntity userPropertiesEntity;

Spring, Hibernate : Lazy initialization exception for many-to-many mapping

I am working on a Spring-MVC application in which I am trying to add many-to-many mapping for an already existing one-to-many mapping between two entities. Two entities which we have in the project are GroupSection and GroupNotes.
For one of the task in project, I had to introduce a many-to-many mapping between GroupSection and GroupNotes, but I am getting a lazy initialization exception.
Error :
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: failed to lazily initialize a collection of role: com.tooltank.spring.model.GroupSection.groupSections, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.tooltank.spring.model.GroupSection["groupSections"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.tooltank.spring.model.GroupSection.groupSections, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.tooltank.spring.model.GroupSection["groupSections"])
Here is the controller method which was called:
#RequestMapping(value = "/sections/get/{canvasid}")
public #ResponseBody List<GroupSection> getAllSectionsForCanvas(#PathVariable("canvasid") int canvasid) {
boolean value = this.personService.getCanvasValuesForCanvas(canvasid);
return this.groupSectionService.listGroupSectionByCanvasid(canvasid, value);
}
DAO method(Service method just calls the DAO method) :
#Override
#Transactional(readOnly = true)
public List<GroupSection> listGroupSectionByCanvasid(int mcanvasid) {
try {
Session session = this.sessionFactory.getCurrentSession();
org.hibernate.Query query = session.createQuery("From GroupSection as msection where " +
"msection.currentcanvas.mcanvasid=:mcanvasid and msection.sectionDisabled=false and msection.sectionInActive=false");
query.setParameter("mcanvasid", mcanvasid);
return query.list();
}catch (Exception e){
e.printStackTrace();
return null;
}
}
GroupSection model :
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import javax.persistence.*;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
#Entity
#Table(name = "membersection")
public class GroupSection {
// Below is self-mapping, required for one of the task, works.
#JsonIgnore
#ManyToOne
#JoinColumn(name = "owned_section_id", nullable = true)
private GroupSection primarySection;
#OneToMany(mappedBy = "primarySection", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
private Set<GroupSection> groupSections = new HashSet<>();
// Many to many mapping, I had lazy loading before, but tried Eager to see if error goes, it doesn't. :
#ManyToMany(fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
#JoinTable(name = "sectionjunction",joinColumns = {#JoinColumn(name = "msectionid")},
inverseJoinColumns = {#JoinColumn(name = "mnoteid")})
private Set<GroupNotes> groupNotesSet = new HashSet<>();
// One to many mapping below :
#OneToMany(mappedBy = "ownednotes", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
#JsonIgnore
private Set<GroupNotes> sectionsnotes = new HashSet<>();
}
GroupNotes :
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import javax.persistence.*;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
#Entity
#Table(name = "groupnotes")
public class GroupNotes implements Serializable {
#JsonIgnore
#ManyToMany(mappedBy = "groupNotesSet",fetch = FetchType.EAGER)
private Set<GroupSection> groupSectionSet = new HashSet<>();
#ManyToOne
#JoinColumn(name = "msectionid",nullable = true)
#JsonIgnore
private GroupSection ownednotes;
// Self mappings :
#JsonIgnore
#ManyToOne
#JoinColumn(name = "owned_note_id", nullable = true)
private GroupNotes primaryNote;
#OneToMany(mappedBy = "primaryNote", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE)
private Set<GroupNotes> groupNotesSet = new HashSet<>();
}
What am I doing wrong? Is it possible to simultaneously have one-to-many and many-to-many mapping between 2 classes. If yes, then what's the deal with that error. Kindly let me know. THank you. :-)
When calling listGroupSectionByCanvasid you open a transaction and a session. When the call return the session is closed. And when spring is returning the value it tries to read you object and because of lazy loading of your manytomany relation groupNotesSet and groupSections are hibernate collections that need the session. And in your case session doesn't exsit anymore.

How to create a model, in Spring, from json where the foreign key is referenced as a long attribute?

One Group has many Users:
Group
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.*;
import java.util.Collection;
import java.util.List;
#Entity
#Table(name = "GROUPS")
public class Group {
#Id
#Column(name = "ID")
private Long ID;
#Column(name = "NAME")
private String NAME;
//#JsonManagedReference
#OneToMany(mappedBy = "group"
//, fetch = FetchType.EAGER
//, cascade = CascadeType.ALL
)
private List<Users> itsUser;
//getters and setters are omitted for clarity
}
Users
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.persistence.*;
import static javax.persistence.GenerationType.SEQUENCE;
#Entity
#Table(name = "USERS")
#SequenceGenerator(name = "SEQUENCE_USER_ID", //my own name in java (unique)
sequenceName = "GENERATOR_SEQUENCE_USERS", //in database
initialValue = 1,
allocationSize = 1)
public class Users {
#JsonProperty(value = "id") //these play a role when both reading or writing
#Id
#Column(name = "ID")
#GeneratedValue(strategy=SEQUENCE, generator="SEQUENCE_USER_ID")
private Long ID;
#JsonProperty(value = "name")
#Column(name="NAME")
private String NAME;
#JsonProperty(value = "username")
#Column(name="USERNAME")
private String USERNAME;
#JsonProperty(value = "password")
#Column(name="PASSWORD")
private String PASSWORD;
#JsonProperty(value = "email")
#Column(name="EMAIL")
private String EMAIL;
#JsonProperty(value = "picture") //Now it works with both mypic and picture as json keys
#Column(name="PICTURE")
private String PICTURE;
//#Column(name="GROUP_ID") //we already have a ManyToOne for this, we cannot repeat it
#JsonProperty(value = "groups_id")
//to ignore it in jpa (http://stackoverflow.com/questions/1281952/jpa-fastest-way-to-ignore-a-field-during-persistence)
private Long itsGroupId;
#Transient
public Long getItsGroupId() {
if(itsGroupId == null) {
this.itsGroupId = group.getID();
} else {
//nop
}
return itsGroupId;
}
public void setItsGroupId(Long itsGroupId) {
this.itsGroupId = itsGroupId;
}
//#JsonIgnore
//#JsonProperty(value = "groups_id")
//#JsonBackReference
#ManyToOne(optional = false, targetEntity = Group.class)
#JoinColumn(
name = "GROUP_ID", //column name
referencedColumnName = "ID" //reference name
)
private Group group;
//getters and setters are omitted for clarity
}
We are using Spring with Spring-data and Jackson to do things automagically but we cannot configure the magic:
We are trying to stick on the following constraints at the same time:
1) Keep the ability to have a reference to the groupId and the ManyToOne relationship group.
This is easy to be achieved by putting #Transient annotation at the groupId because #Column is not allowed since we have already declared the #ManyToOne annotation. You also have to implement the getGroupId method accordingly.
2) Return a json of Users class that contains the groups_id.
This can be implemented by setting the #JsonProperty annotation.
3) Create a user class, and also save it in the database, by a json. The json contains groups_id which has as a value an integer for the foreign key.
This does not work because by setting it #Transient above, then the system refuses to save in the database something that is transient or at least this is how we interpret this exception:
HTTP Status 500 - Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: not-null
property references a null or transient value: com.pligor.mvctest.models.Users.group;
nested exception is org.hibernate.PropertyValueException:
not-null property references a null or transient value: com.pligor.mvctest.models.Users.group
On the backend do something like this:
Group group = groupRepository.findById(userResource.getGroupId());
if (group != null) {
User user = new User(userResource);
user.setGroup(group);
userRepository.save();
}
The idea behind this is that you need to fetch the group from the DB, to be able to link it with the newly created User

Categories