I have a two problem entityes fields in my project:
First:
public class User implements UserDetails {
private static final long serialVersionUID = -8442780593066407492L;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "user_role",
joinColumns = {#JoinColumn(name = "user_id")},
inverseJoinColumns = {#JoinColumn(name = "role_id")})
private Set<UserRole> userRoles = new HashSet<UserRole>();
#OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE)
private Set<CommentReserv> comments = new HashSet<CommentReserv>();
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> result = new
ArrayList<SimpleGrantedAuthority>();
for (UserRole userRole: userRoles) {
result.add(new
SimpleGrantedAuthority(userRole.getListRole().name()));
}
return result;
}
...
}
Second:
public class CommentReserv implements Serializable {
private static final long serialVersionUID = 1579363480188238317L;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne
#JoinColumn(name = "reservation_id")
private Reservation reservation;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private User user;
...
}
Third:
public class Reservation implements Serializable{
private static final long serialVersionUID = -9007238193656173229L;
#Id
#Column(name = "id")
private String id = generateId();
...
#OneToMany(mappedBy = "reservation", cascade = CascadeType.REMOVE)
private Set<CommentReserv> comments = new HashSet<CommentReserv>();
...
Then i get Reservation and User from DB...
Reservation reservation = this.reservationRepository.getReservationById(params.get("reservationId").toString());
User currentUser = this.userRepository.getUser(principal.getName());
(I checked it. User is loaded correctly.)
And set it to new CommentReserv instance.
commentReserv.setReservation(reservation);
commentReserv.setComment(params.get("comment").toString());
commentReserv.setUser(currentUser);
When i trying to save new CommentReserv, i get User copy in my DB.
I tryed to remove cascadetype from CommentReserv, but it produces TransientObjectException.
What is wrong with my code? Second night without sleep...
In my DB i have one user with id=0. It is strange, but hibernate assume that if user id = 0 then user is not exists in DB. Really strange. I just change id to 1 and it's work fine.
Related
I'm stuck at deal with this problem. I have 'Review Entity', and 'Heart Entitiy'. And I tried to show them homepage and detailpage separately!
Long countHeartByBookReviewId(Long bookReview_id);
i used jpa query method for showing how many heart it gets in details page..
and now i want to show review descending related to heart count in main page!
how can i make the code..?
#Entity
public class BookReview extends Timestamped {
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Id
private Long id;
...
#Column
private String review;
#JoinColumn(name = "member_id", nullable = false)
#ManyToOne(fetch = FetchType.EAGER)
private Member member;
#OneToMany(mappedBy = "bookReview" , cascade = CascadeType.REMOVE)
private List<Comment> comment;
#JsonIgnore
#OneToMany(mappedBy = "bookReview", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Heart> heart;
and the other entitiy is here.
public class Heart {
#GeneratedValue(strategy = GenerationType.AUTO)
#Id
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "bookReview_id")
private BookReview bookReview;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "member_id")
private Member member;
and this is function for get menthod...
public ResponseDto<?> getHome() {
List<BookReview> book_review = book_reviewRepository.findAllByOrderByHeartDesc();
List<HomeResponseDto> book_reviewResponseDtoList = new ArrayList<>();
for (BookReview home : book_review) {
book_reviewResponseDtoList.add(HomeResponseDto.builder()
.id(home.getId())
.username(home.getMember().getUsername())
.thumbnail(home.getThumbnail())
.title(home.getTitle())
.author(home.getAuthor())
.publisher(home.getPublisher())
.review(home.getReview())
.heart(heartRepository.countHeartByBookReviewId(home.getId()))
.createdAt(home.getCreatedAt())
.modifiedAt(home.getModifiedAt())
.build()
);
}
return ResponseDto.success(book_reviewResponseDtoList);
}
please help me ......
I have a User Entity.
#Entity
#Table(name = "t_login_user")
public class User extends Auditable<Long> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
private Long id;
#Column(name = "user_uid")
private String userUid;
#Column(name = "user_name")
private String userName;
#OneToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name="primary_role_id")
private Role primaryRole;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "t_login_user_role_map", joinColumns = #JoinColumn(name = "user_id"), inverseJoinColumns = #JoinColumn(name = "role_id"))
private List<Role> roles;
}
My Role Entity is
#Entity
#Table(name = "t_login_role")
public class Role extends Auditable<Long> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="role_id")
private Long roleId;
#Column(name="role_code")
private String roleCode;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "t_login_role_priv_map", joinColumns = #JoinColumn(name = "role_id"), inverseJoinColumns = #JoinColumn(name = "priv_id"))
private List<Privilege> privileges;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "t_login_role_menu_map", joinColumns = #JoinColumn(name = "role_id"), inverseJoinColumns = #JoinColumn(name = "menu_id"))
private List<Menu> menus;
}
My Menu Entity is
#Entity
#Table(name = "t_login_menu")
public class Menu extends Auditable<Long> implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="id")
private Long id;
#Column(name="menu_text")
private String menuText;
#Column(name="menu_icon")
private String menuIcon;
#Column(name="menu_url")
private String menuURL;
}
As you can see my Role has multiple Privileges and Multiple Menus. The problem I face is that when I have a code like
LoggedinUser liu = (LoggedinUser)authentication.getPrincipal();
List<Menu> menus = liu.getPrimaryRole().getMenus();
If I have two privileges say READ_DATA and WRITE_DATA
And three Menus 1. HOME 2.USER 3.PROFILE
my menus variable has a value of [HOME,HOME,USER, USER, PROFILE, PROFILE] (i.e. 2 privileges * 3 Roles)
I suspect that this is due to my Role entity having more than one #ManyToMany annotations.
I tried to search online and Stackoverflow but no results.
Anybody face this issue? Am i doing something fundamentally wrong?
Okay. I understand where the cross join happens. Since both the ManyToMany are being EAGER loaded, this is where the Cross Join Happens.
If I change to LAZY Load then the issue disappears. Slight performance hit on LAZY load, but thats fine since I do it only once and store the result in the session.
I have User entity:
public class User implements IStandarizedEntity {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Long id;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "web.user_role",
joinColumns = {
#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {
#JoinColumn(name = "role_id", referencedColumnName = "id")})
#Size(min = 1, max = 10)
private List<Role> roles = new ArrayList<>();
A a Role entity:
public class Role implements IStandarizedEntity {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Long id;
#Column(name = "type")
#Enumerated(EnumType.STRING)
private ERole type;
I am using hibernate like a jpa provider. I want to only get users with specific role. I wrote named query to retrieve all users and now I am trying to use #Filter to retrieve only users with specified role type.
What I achieved is that I can retrieve all users and next while loading roles I can load filtered roles list but it is not what I want to do.
You can just filter the role when querying.
For example:
Select u from User u join fetch u.roles r where r.type = :roleType;
Join fetch will return all users with roles matching your filter.
I have a confusing problem which I haven't figured out how to solve. if you can offer a suggestion of how I can fix my problem I would be grateful.
So I have the following entity relationship model here.
The mapping of User.class is:
#Entity
#Table(name = "CRM_USER")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USER_ID")
private Long id;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "LAST_NAME")
private String lastName;
#Column(name = "BIRTHDATE")
private Date birthDate;
#Column(name = "EMAIL")
private String email;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private UserAdditionalInfo additionalInfo;
#ManyToOne
#JoinColumn(name = "TEAM_FK")
private Team team;
#ManyToOne
#JoinColumn(name = "JOB_FK")
private Job job;
#ManyToOne
#JoinColumn(name = "ORGANIZATION_FK", nullable = false)
private Organization organization;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private Security security;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "INFO_FILE_FK")
private InfoFile profilePicture;
#ManyToOne
#JoinColumn(name = "COUNTRY_FK")
private Country country;
// Getters and Setters
}
The mapping of Comment.class is:
#Entity
#Table(name = "CRM_COMMENT")
public class Comment implements Serializable {
private static final long serialVersionUID = -104145851368148154L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "COMMENT_ID")
private Long id;
#ManyToOne
#JoinColumn(name = "ARTICLE_ID")
private Article article;
#ManyToOne
#JoinColumn(name = "USER_FK", nullable = false)
private User createdUser;
#Column(nullable = false)
private String comment;
#Column(name = "CREATION_DATE", nullable = false)
private Date creationDate;
#Column(name = "MODIFICATION_DATE")
private Date modificationDate;
#OneToMany(cascade = {CascadeType.ALL}, orphanRemoval = true)
#JoinTable(name = "CRM_COMMENT_LIKE",
joinColumns = {#JoinColumn(name = "COMMENT_ID")},
inverseJoinColumns = {#JoinColumn(name = "USER_ID")})
private Set<User> fans = new LinkedHashSet<>();
// Getters and Setters
}
The mapping of Article.class is:
#Entity
#Table(name = "CRM_ARTICLE")
public class Article implements Serializable {
// other properties
#OneToMany(mappedBy = "article", cascade = {CascadeType.ALL}, orphanRemoval = true)
#OrderBy("id DESC")
private Set<Comment> comments = new LinkedHashSet<>();
// Getters and Setters
}
The problem is related to my ManyToMany relation between the Comment and User - CRM_COMMENT_LIKE.
Actually, when I add some new 'fan' into Comment, there is no problem.
#Override
public boolean giveAnLikeToComment(Long commentId, User fan) {
Comment comment = commentDao.get(commentId);
if (Objects.isNull(comment)|| BooleanUtils.isTrue(comment.getFans().contains(fan))) {
return false;
}
comment.getFans().add(fan);
commentDao.update(comment);
return true;
}
The problem arises when I try to delete some comment, which has at least one 'like'/'fan' to it.
#Override
public boolean deleteCommentById(final Long commentId) {
Comment comment = commentDao.get(commentId);
if (Objects.nonNull(comment)) {
Article article = comment.getArticle();
article.getComments().remove(comment);
comment.setFans(null); // This line fix the problem
articleDao.update(article);
return true;
}
return false;
}
So in this case, I manage the relation between an Article ( which is parent of a Comment) and the comment itself. This is easy, because the connection between them is bidirectional. But what about the fans? I can't remove the connection between a Comment and CRM_COMMENT_LIKE relation, because the User doesn't know about the CRM_COMMENT_LIKE or about the Comments. Something more, I want, when I remove a Comment, to remove and all created relations in CRM_COMMENT_LIKE. But I'm prevent, because Hibernate throws an exception which says:
deleted object would be re-saved by cascade (remove deleted object from associations):
[crm.alltogether.core.admin.model.User#1]; nested exception is
org.hibernate.ObjectDeletedException: deleted object would be re-saved
by cascade (remove deleted object from associations):
[crm.alltogether.core.admin.model.User#1]
This is my issue, so if you have a suggestion, I would be glad to read it :)
Best Regards,
You need to have a orphanRemoval=true cascading between Article and Comment. Then you would do this.
if (Objects.nonNull(comment)) {
Article a = comment.getArticle();
a.getComments().remove(comment);
articleDao.saveOrUpdate(a);
return true;
}
This will take care of deleting orphan comment, as you already have a cascade all on fans it would delete that association as well. I would suggest you to play around with cascade orphanRemoval=true on fans as well.
Is it possible to expose a manytomany relationship that uses a join entity (that contains extra data columns), below is my entities;
I'm trying to get 'purchases' to show in REST, I've put in 'products' as an example of a working REST mapping;
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, targetEntity = Purchase.class, orphanRemoval = true)
#JoinColumn(name = "user_id", updatable = false)
private List<Purchase> purchases = new ArrayList<>();
#ManyToMany
#JoinColumn(name = "user_id", updatable = false)
private List<Product> products = new ArrayList<>();
}
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
}
#Entity
public class Purchase implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#ManyToOne
#JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
#ManyToOne(targetEntity = Prodect.class)
#JoinColumn(name = "product_id", referencedColumnName = "id")
private Product product;
#Column(name = "purchase_date")
private Date purchaseDate;
}
So if i send the REST call;
[GET http://localhost:8080/webapp/users/1]
It returns links for [http://localhost:8080/webapp/users/1/products] but not for [http://localhost:8080/webapp/users/1/purchases]
worked out what the issue was; I need to create a JpaRepository for the Purchase entity. Soon as I added that, the REST links for purchases are available.