I'm currently having this issue: I have 3 tables: users, roles and users_roles as in the picture below:
whenever I edit any of the record in users table, the record of that user in the users_roles table will be lost.
For example, I changed the username of the user which holds the userId = 2, then in the users_roles table, the row of userId = 2 will be lost.
Anybody has any ideas of this problem? I'm using Spring with Hibernate
*UPDATE
In my Role.java
#ManyToMany(fetch = FetchType.EAGER, mappedBy = "roles")
private List<User> users;
In my User.java
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "users_roles", joinColumns = #JoinColumn(name = "userId", nullable = false) , inverseJoinColumns = #JoinColumn(name = "roleId", nullable = false) )
private List<Role> roles;
And in my UsersRoles.java
#Id
#Column(name="userId")
private int userId;
#Id
#Column(name="roleId")
private int roleId;
This is the DAO implementation method I used for Edit
#Override
public void edit(User user) {
session.getCurrentSession().saveOrUpdate(user);
}
P/S: this not only happens when I edit with my web-app, but also happens when I edit directly in MySQL environment. I don't know...
Related
I run my app, and everything work nicely. My entities are created in the DB, but in spite of this, I have next exception.
Error executing DDL "alter table user add constraint UK_ob8kqyqqgmefl0aco34akdtpe unique (email)" via JDBC Statement
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "alter table user add constraint UK_ob8kqyqqgmefl0aco34akdtpe unique (email)" via JDBC Statement
at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final]
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlString(SchemaCreatorImpl.java:502) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final]
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlStrings(SchemaCreatorImpl.java:486) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final]
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.createFromMetadata(SchemaCreatorImpl.java:402) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final]
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.performCreation(SchemaCreatorImpl.java:176) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final]
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:144) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final]
at org.hibernate.tool.schema.internal.SchemaCreatorImpl.doCreation(SchemaCreatorImpl.java:128) ~[hibernate-core-6.1.5.Final.jar:6.1.5.Final]
... 35 common frames omitted
My properties table is create
My Entities
Entity
#Table (name = "User")
public class User {
#Id
#GeneratedValue (strategy = GenerationType.IDENTITY)
#Column (name = "user_id", nullable = false)
private Long userId;
#Basic
#Column (name = "email", nullable = false, length = 4096, unique = true)
private String userEmail;
#Basic
#Column (name = "password", nullable = false, length = 4096)
private String userPassword;
#ManyToMany (fetch = FetchType.EAGER)
#NotFound(action = NotFoundAction.IGNORE)
#JoinTable (name = "user_role",
joinColumns = {#JoinColumn (name = "user_id")},
inverseJoinColumns = {#JoinColumn (name = "role_id")})
private Set <Role> roles = new HashSet<>();
#OneToOne (mappedBy = "user")
private Student student;
#OneToOne (mappedBy = "user")
private Instructor instructor;
public User () {}
If you know please say what I need to do, thanks!
I have two entities User:
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long userID;
#Column(name = "userHashedPassword")
private String password;
#Column(name = "userName")
private String userName;
#Column(name = "userEmail")
private String email;
#Transient
private List<String> groups = new LinkedList<>();
#ManyToMany
#JoinTable(name = "UserRoles",
joinColumns = #JoinColumn(
name = "userID"),
inverseJoinColumns = #JoinColumn(
name = "roleID"))
private Set<Role> roles = new HashSet<>();
#OneToMany(mappedBy = "user")
private Set<Rating> ratings;
protected User(){}
public User(String userHashedPassword, String userName, String email, Set<Role> roles){
this.password = userHashedPassword;
this.userName = userName;
this.email = email;
this.roles = roles;
}
//getters and setters
}
And Group:
#Table(name="FocusGroups")
#Entity
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "groupID")
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long groupID;
private String groupName;
#ManyToMany
#JoinTable(name = "GroupMembers",
joinColumns = #JoinColumn(
name = "groupID"),
inverseJoinColumns = #JoinColumn(
name = "userID"))
private Set<User> groupMembers = new HashSet<>();
#ManyToOne(fetch = FetchType.EAGER, optional = true)
#JoinColumn(name="frameworkID", nullable = true)
private Framework framework;
public Group(){}
public Group(String groupName, Set<User> groupMembers, Framework framework) {
this.groupName = groupName;
this.groupMembers = groupMembers;
this.framework = framework;
}
//getters setters
}
When I delete a User, I want to remove them from group members, however it fails due to foreign key constraint: java.sql.SQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (capripol.groupmembers, CONSTRAINT FK98tbu0sjfsn1m5p340dn0v8wo FOREIGN KEY (userID) REFERENCES users (userID))
How do I work around this?
Well, I will try to answer: First of all, it is rather strange you refer on Groups in user
entity like that:
#Transient
private List<String> groups = new LinkedList<>();
It this case, you will not have a column group in user table in database, hence you have to first perform removal from group_members for an all groups:
delete from group_members where userid = <user_id_you_want_to_remove>;
And only after your JoinTable table does not contain any refers to user with <user_id_you_want_to_remove>, than you can execute
delete from users where userid = 1;
Note: there is no matter you do it by spring data (e.g. deleteById(Long id) and using #Query annotation specify the query above in SQL or HQL, up to you) - this will work. But I highly recommend you to reconsider you database structure - it is not cute to store only one entity.
I have a Folder entity in Hibernate, like so:
#Entity
#Table(name = "folders")
public class Folder {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "folder_id", unique = true, nullable = false)
private int id;
#NonNull
#Column(name = "name", length = 100, unique = true, nullable = false)
private String name;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "parent", orphanRemoval = true)
#Column(name = "sub_folders")
private Set<Folder> childFolders = new HashSet<>();
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JsonIgnore
#JoinColumn(name = "parent", referencedColumnName = "folder_id", nullable = true)
private Folder parent;
public Folder() {
}
}
I'm trying to write a finder method or custom query which will do what I wrote in the subject.
So if I send a request going like folders/{parent_folder_id}, let's say value being 1, I should get objects 4 and 5, but without their children, so not including 6,7,8 and 9.
Ideally, hibernate query would be preferred. If not, any sql language is also fine. I'll try to tumble it up to hibernate.
This is what I got, I still get children...
#Query(value = "Select * from folders f where f.parent = ?1 ", nativeQuery = true)
Set<Folder> getFolders(int folder_id);
I think this should work:
make the default fetchtype lazy:
#OneToMany(fetch = FetchType.EAGER, mappedBy = "parent", orphanRemoval = true)
#Column(name = "sub_folders")
private Set<Folder> childFolders = new HashSet<>();
Use a JOIN FETCH in order to eagerly fetch the relationships you want.
SELECT f FROM folders f JOIN FETCH f.childFolders
You probably can achieve something similar with entity graphs but I'm not sure about their interaction with queries.
I got what I need with following query:
#Query(value = "Select folder_id, name, parent From folders f Where f.parent = ?1", nativeQuery = true)
This will give me just name of the folder and its Id.
I have mapped a one to many relationship between a user and an admin as shown in the user class
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "userId")
private Long id;
#Column(nullable = false)
private String name;
#Column(unique = true, nullable = false)
private String email;
#Column(nullable = false)
private long timestamp;
#OneToOne
#JoinColumn(name = "adminId")
Admin admin;
Now I am trying to save a user by inserting a value of 1 to the adminId field in the users table using SessionFactory of hibernate as shown
public void save(User user) {
//User userAdmin = new User();
long id = 1 ;
user.setId(id);
getSession().save(user);
}
EDITTED
Considering getters and setters, these are the fields in the admin table
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "adminId")
private Long id;
#Column(nullable = false)
private String name;
#Column(nullable = true)
private String department;
My challenge is that when I save, nothing gets inserted (that is value of 1) on the adminId field referencing the admin foreign key in the users table.
Kindly assist!
You'll have to get the Admin entity with id 1 first and then set it on the new User:
#Transactional
public void save(User user) {
Admin admin = getSession.createQuery("from Admin a where a.id = ?)
.setParameter(0, 1);
user.setAdmin(admin);
getSession().save(user);
}
I have an entity called User with two many-to-many relationships: User -mtm - Role and User -mtm - Course
public class User {
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "users_roles",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "role_id", referencedColumnName = "id")})
private List<Role> userRoles;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "users_courses",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "course_id", referencedColumnName = "id")})
private List<Course> orderedCourses;
}
In Course entity:
public class Course {
#ManyToMany(mappedBy = "orderedCourses")
private List<User> participants;
}
It looks similar in the Role entity.
When user with e.g. two roles assigned enrolls himself to some course (means that course is added to his orderedCourses list), he gets this course twice.
So the user with two roles gets registered for the same course twice, user with 3 roles gets it three times etc.
It is noticeable in the junction table in the database. (one user has the same course few times which is unacceptable).
Looks like one ManyToMany relationship has an impact on another. But I don't know what is wrong.
Everything is persisted to MySQL database by Hibernate (via Spring Data JPA)