Hibernate multiple attribute mappings same table deletion - java

I have a hopefully simple problem in Hibernate. I have Users and Projects. The users_projects (in my case user_project_association) has an extra attribute "role" to say if the user is project leader or normal user.
#OneToMany(mappedBy = "project", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#LazyCollection(LazyCollectionOption.EXTRA)
private Set<UserProjectAssociation> userProjectAssociations = new HashSet<>();
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "user_project_role",
joinColumns = #JoinColumn(name = "project_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
#WhereJoinTable(clause = "role_id=7")
#Setter(AccessLevel.NONE)
private Set<User> projectLeaders = new HashSet<>();
#ManyToMany
#JoinTable(name = "user_project_role",
joinColumns = #JoinColumn(name = "project_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
#LazyCollection(LazyCollectionOption.EXTRA)
#Setter(AccessLevel.NONE)
private Set<User> users = new HashSet<>();
If i try to remove a project via "getEntityManager().remove(persistentInstance);" I can see in the log this sql statements:
Hibernate:
/* delete collection com.XXX.core.model.Project.users */ delete
from
user_project_role
where
project_id=?
Hibernate:
/* delete collection com.XXX.core.model.Project.projectLeaders */ delete
from
user_project_role
where
project_id=?
and (
role_id=7
)
Hibernate:
/* delete com.XXX.core.model.UserProjectAssociation */ delete
from
user_project_role
where
id=?
and the error message:
2016-05-25 10:05:57 INFO AbstractBatchImpl:208 - HHH000010: On release of batch it still contained JDBC statements
and nothing is deleted. Does anyone have an idea to get my projects deleted?
Thanks a lot :)

Puh. I found (the or a) solution for it. It's not really elegant, but it's working:
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "user_project_role",
joinColumns = #JoinColumn(name = "project_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
#WhereJoinTable(clause = "role_id=7")
#SQLInsert(sql = "insert into user_project_role (project_id, user_id, role_id) values (?, ?, 7)")
#SQLDelete(sql = "delete from user_project_role where project_id=? and user_id=? and role_id = 7")
#Setter(AccessLevel.NONE)
private Set<User> projectLeaders = new HashSet<>();
#ManyToMany
#JoinTable(name = "user_project_role",
joinColumns = #JoinColumn(name = "project_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
#LazyCollection(LazyCollectionOption.EXTRA)
#WhereJoinTable(clause = "role_id=8")
#SQLInsert(sql = "insert into user_project_role (project_id, user_id, role_id) values (?, ?, 8)")
#Setter(AccessLevel.NONE)
private Set<User> projectUsers = new HashSet<>();
So I removed the userProjectAssociations attribute and added customized #SQLInsert and #SQLDelete Statements.
If I want to get all Users including normal users and project leaders I use this method:
public Set<User> getAllUsers() {
Set<User> allUsers = new HashSet<>();
allUsers.addAll(projectLeaders);
allUsers.addAll(projectUsers);
return allUsers;
}

Related

Vaadin/Spring duplicated error in a ManytoMany Join

I have a User class and a Movie class which I want to merge into separate Lists. Once for movies that have been watched and one for the watchlist. Separately everything is fine but it seems that when I want to put them on both merges I get a duplication error even though they are saved in differently named columns.
#ManyToMany(cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER)
#JoinTable(name = "user_watch_list", joinColumns = #JoinColumn(name = "watche_User_ID", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "watch_Movie_id",referencedColumnName = "movieID"))
private List<Movie> watchList = new ArrayList<>();
#ManyToMany(cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER)
#JoinTable(name = "user_watched_movies", joinColumns = #JoinColumn(name = "watcheed_User_ID",referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "watched_movie_id",referencedColumnName = "movieID"))
private List<Movie> watchedMovies = new ArrayList<>();

Many To Many order by time it got added to post

#Entity
public class Post{
private Long id;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "tag_posts", joinColumns = #JoinColumn(name = "post_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "post_id", referencedColumnName = "id"))
private Set<Tag> hashtags= new LinkedHashSet<>();
}
Hello I would like to sort hashtags by right order they got added in to post, is anything like this possible?
Or would I just change type to List? Wouldnt this affect performance?
Thanks.
I assume you want to retrieve Post along with the tags but you want tags in the order it got added to the Post.
You can use #OrderBy annotation to get the list of tags while retrieving.
#Entity
public class Post{
private Long id;
#OrderBy(value="orderField")
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "tag_posts", joinColumns = #JoinColumn(name = "post_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "post_id", referencedColumnName = "id"))
private Set<Tag> hashtags= new LinkedHashSet<>();
}
If you want to create a column in the join table which will keep the same order you can use #OrderByColumn("orderField")

how to count items of OneToMany element via Spring data

i have a user Entity :
#Entity
#Table(name = "user")
#Data
public class UserEntity extends BaseEntity {
#Column(name = "full_name")
private String fullName;
....
#OneToMany(cascade = CascadeType.REMOVE)
#JoinTable(name = "user_post",
joinColumns = {#JoinColumn(name = "user_id")},
inverseJoinColumns = {#JoinColumn(name = "post_id")})
private Set<PostEntity> posts;
#ManyToMany
#JoinTable(name = "user_followers",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "follower_id", referencedColumnName = "id")})
private Set<UserEntity> followers = new HashSet<>();
#ManyToMany
#JoinTable(name = "user_followings",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "following_id", referencedColumnName = "id")})
private Set<UserEntity> followings = new HashSet<>();
}
now i want to count followers of a user.
i can get list of followers and use list.size() but this is not good . i just want count of them not whole objects .is this possible by a method in my UserRepostiory that extends JpaRepostiory or a native query ?
I suggest you to use JPQL syntax. In your UserRepository you can add count methods. Please try :
#Query("select count(p) from User u join u.posts p where u.id = ?1")
long countPosts(Long id);
#Query("select count(f) from User u join u.followers f where u.id = ?1")
long countFollowers(Long id);
#Query("select count(f) from User u join u.followings f where u.id = ?1")
long countFollowings(Long id);

Referential integrity constraint violation - failing when add more then 2 records

When im loading my initial tests data i retrieve integrity constraint violation exception. It only occurs, when im adding more then 2 records, using addShift method. Im using h2, in memory database.
Loading:
public void load() {
shiftService.addShift(1, LocalDate.now(), ShiftType.DAY, 1);
shiftService.addShift(2, LocalDate.now().plusDays(1), ShiftType.NIGHT, 1);
shiftService.addShift(2, LocalDate.now().plusDays(5), ShiftType.NIGHT, 2);
}
Shift Service:
#Transactional
public void addShift(long userId, LocalDate shiftDate, ShiftType shiftType, long groupId) {
Optional<User> user = userService.findOne(userId);
if (user.isPresent()) {
Optional<Group> group = groupService.getOne(groupId);
if (group.isPresent()) {
Shift shift = new Shift(shiftDate, shiftType, group.get());
user.get().addShift(shift);
}
}
}
Caused by:
org.h2.jdbc.JdbcSQLException: Referential integrity constraint
violation: "FKG5R8KJRL3GG3EKESMHT77GO7L: PUBLIC.SHIFT FOREIGN KEY(ID)
REFERENCES PUBLIC.GROUPS(ID) (3)"; SQL statement:
insert into shift (id, group_id, shift_date, shift_type) values (null, ?, ?,
?) [23506-196]
Model:
Shift:
#Entity
public class Shift {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private LocalDate shiftDate;
private ShiftType shiftType;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "user_shifts", joinColumns = #JoinColumn(name = "shift_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
private Set<User> users = new HashSet<>();
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "group_id")
private Group group;
Group:
#Entity
#Table(name = "groups") // Group is reserved name in SQL
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "user_group", joinColumns = #JoinColumn(name = "group_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
private Set<User> users = new HashSet<>();
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "moderator_group", joinColumns = #JoinColumn(name = "group_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
private Set<User> moderators = new HashSet<>();
#OneToMany(mappedBy = "id", cascade = CascadeType.ALL)
private Set<Shift> shifts;
User:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String email;
private String password;
private String firstName;
private String lastName;
private String phone;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(
name = "user_authority",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "authority_name", referencedColumnName = "name")}
)
private Set<Authority> authorities = new HashSet<>();
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
name = "user_group",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "group_id", referencedColumnName = "id")}
)
private Set<Group> usingGroups = new HashSet<>();
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
name = "moderator_group",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "group_id", referencedColumnName = "id")}
)
private Set<Group> moderatingGroups = new HashSet<>();
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(
name = "user_shifts",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "shift_id", referencedColumnName = "id")}
)
private Set<Shift> shifts = new HashSet<>();
Do you have any ideas why i got this exception?
Your mapping in Group is wrong.
#OneToMany(mappedBy = "id", cascade = CascadeType.ALL)
private Set<Shift> shifts;
This should be rather:
#OneToMany(mappedBy = "group", cascade = CascadeType.ALL)
private Set<Shift> shifts;
Explanation:
Hibernate is adding a foreign key constraint between id in shift and id in group. You are probably adding 2 groups, and after you try to add more than 2 shifts, the constraint isn't fulfilled, because a group with id 3 doesn't exist.

How to Ignore a whole Mapped/Joined Model(Class) in Spring hibernate.

I have three tables. tbl_vendor and tbl_category tables are mapped using #ManyToMany relation. When I am getting 'Vendors' under a particular 'Category' I am also getting 'Areas' because tbl_vendor and tbl_area are also mapped using #ManyToMany.
relations:
in tbl_vendor Model :
#ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
#JoinTable(name = "tbl_category_vendor", joinColumns = {#JoinColumn(name = "vendor_id")}, inverseJoinColumns = {#JoinColumn(name = "category_id")})
private Set<Category> categories = new HashSet<>();
....
#ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
#JoinTable(name = "tbl_area_vendor", joinColumns = {#JoinColumn(name = "vendor_id")}, inverseJoinColumns = {#JoinColumn(name = "area_id")})
private Set<Area> areas = new HashSet<>();
in tbl_category Model :
#JsonIgnore
#ManyToMany(cascade = CascadeType.DETACH, mappedBy = "categories", fetch = FetchType.LAZY)
private List<Vendor> vendors = new ArrayList<>();
in tbl_area Model :
#JsonIgnore
#ManyToMany(mappedBy = "areas", fetch = FetchType.LAZY)
private List<Vendor> vendors = new ArrayList<>();
I have a particular case where I don't need this 'Area' with 'Vendor'.
is there any way to ignore already mapped 'Area' from 'Vendor' using JpaRepository in some particular case ?

Categories

Resources