Hibernate ManyToMany HQL issue - java

My MySql tables:
db tables
And My Two Entity Classes are
#Entity
public class Tweet {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="tweet_id")
private int tweetId;
private String message;
private Date created;
#ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
#JoinColumn(name="user_id")
private Person person;
...
}
#Entity
public class Person {
#Id
#Column(name = "user_id")
private String userId;
private String password;
private String email;
private String fullName;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "following", joinColumns = { #JoinColumn(name = "user_id") },
inverseJoinColumns = { #JoinColumn(name = "following_id") })
private List<Person> following = new ArrayList<Person>();
...
}
Now I want to display messages of user praveen, and also all the messages mapped to praveen user in the following table. That means praveen user have 2 messages and his following users have 2 messages . Total 4 messages should be displayed. I really don't know how to retrieve this info using any technique in Hibernate. Please help me

Related

role based creation of users in Spring boot

i have Three entities User, Institution and Role.
1)one to many between user and institution
2)and many to many between User and Role
-------user-------
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="user_Id")
private int userId;
#Column(name="name")
private String name;
#Column(name="lastname")
private String lastname;
#Column(name="email")
private String email;
#Column(name="password")
private String password;
#Column(name="isActive")
private boolean isActive;
#Column(name="lastActive")
private String lastActive;
#Column(name="createdDate")
private String createdDate;
#Column(name="isBlocked")
private boolean isBlocked;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "institution_id", nullable = false)
#JsonIgnoreProperties(value = {"user"})
private Institution institution;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "user_has_role",
joinColumns = {
#JoinColumn(name = "user_id", referencedColumnName = "user_id",
nullable = false, updatable = true)},
inverseJoinColumns = {
#JoinColumn(name = "role_id", referencedColumnName = "role_id",
nullable = false, updatable = true)})
#JsonIgnoreProperties(value = {"users"})
private Set<Role> roles = new HashSet<>();
}
-------institution-------
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Entity
#Table(name = "institution")
public class Institution {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="institution_Id")
private int institutionId;
#Column(name="name")
private String name;
#Column(name="type")
private String type;
#Column(name="location")
private String location;
#OneToMany(mappedBy = "institution", fetch = FetchType.LAZY)
#JsonIgnoreProperties(value = {"institution" , "user"})
private Set<User> user;
}
-------role-------
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#ToString
#Entity
#Table(name = "role")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="role_Id")
private int roleId;
#Column(name="name")
private String name;
#Column(name="description")
private String description;
#ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
#JsonIgnoreProperties(value = {"roles"})
private Set<User> users = new HashSet<>();
}
Those are my 3 entities and tables in MySql
i have 7 roles
• Super-User
• Bank-Admin
• Bank-Support
• Bank-Service
• Merchant-Admin
• Merchant-Support
• Merchant-service
The super-User can create a user of any role
#PostMapping("/addUser")
public String addUser(#RequestBody User user) {
String rawpassword = user.getPassword();
String encodedpasswrod = passwordencoder.encode(rawpassword);
user.setPassword(encodedpasswrod);
userrepository.save(user);
return "user saved with name: " + user.getName();
}
this api works and i can set the role to anything in my api json body
But want that if the User is Bank-Admin he can only create Bank-Support and Bank-Service
im trying to create a new API which can only create a user with those 2 specific roles.
and then restrict the bank admin to access the other API that can create users of any kind.
is there any other way to do it and if no how can i do that...
You have to implement your custom implementation of User Entitlement.
Like according to login person, you will get that login person role, and according to your criteria just put validation like check that entity he is trying to add is he eligible to create it.
Map<String, List<String>> roleUserAccessMap = new HashMap<>();
roleUserAccessMap.put("Bank-Admin", Arrays.asList("Bank-Support", "Bank-Service"));
Just check like below
String loginPersonRole="Bank-Admin"; //This value should get from logged-in person context
if(roleUserAccessMap.containsKey(loginPersonRole) && roleUserAccessMap.get(loginPersonRole).contains(newuserrole) ){
//proceed ahead with Add api
}else{
System.out.println("You do not have enough privileage to create Use");
}
This will help you.

Spring boot data rest/jpa #JoinTable insertion

I'm creating a MySQL database as followed :
database design
the Country and Province tables are pre-filled with data. I have the application running and can get stuff no problem, and also the join table person_has_address works when getting.
however, when I insert data using post I want to be able to set the ID of the province, and let spring data jpa just add that number to add_pro_id in the Address table. For example, when I post the following json:
{ "firstName":"bilbo", "lastName":"baggings", "address":{"street":"streetName", "streetNum":3, "zipcode":"1337GG", "city":"TheCity", "province":{"name":"aProvinceName"}} }
jpa should see that aProvinceName exists and grab that id and add that to add_pro_id.
Now it just insert aProvinceName as new value in province and add the new id to add_pro_id.
The person class:
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="per_id")
private int id;
#Column(name="per_name")
private String firstName;
#Column(name="per_surname")
private String lastName;
#Column(name="per_birth_date")
private String birthDate;
#Column(name="per_fax")
private String fax;
#Column(name="per_phone")
private String phone;
#Column(name="per_email")
private String email;
#OneToOne(optional = false, cascade = CascadeType.ALL)
#JoinTable(name="person_has_address", joinColumns = {#JoinColumn(name="pha_per_id", referencedColumnName = "per_id")}, inverseJoinColumns = {#JoinColumn(name="pha_add_id", referencedColumnName = "add_id")})
private Address address;
// getters and setters
This is the person repository:
#RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
List<Person> findByLastName(#Param("name") String name);
}
This is the address class:
#Entity
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="add_id")
private int id;
#Column(name = "add_street")
private String street;
#Column(name="add_street_num")
private int streetNum;
#Column(name="add_zip")
private String zipcode;
#Column(name="add_city")
private String city;
#JoinColumn(name="add_pro_id", referencedColumnName = "pro_id")
#ManyToOne(optional=false, cascade = CascadeType.ALL)
private Province province;
// getters and setters
Province class:
#Entity
public class Province {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="pro_id")
private int id;
#Column(name="pro_name")
private String name;
#ManyToOne
#JoinColumn(name="pro_cou_id")
private Country country;
// getters and setters
And lastly country class:
#Entity
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="cou_id", insertable = false, updatable = false)
private int id;
#Column(name="cou_name", insertable = false, updatable = false)
private String name;
// getters and setters
I've tried adding insertable = false and updatable = false, but the application then just inserts NULL values in my database. I've also tried working with #primarykeyjoins, but to no success.
if anyone knows how I should tackle this problem I would much appreciate it!
Thanks in advance.

JPA Self Referencing Entities

I have a Table called User like this:
public class User
{
private Long userId;
private String username;
//Other fields;
}
Now Lets say the User can have other User friends. So how do I create this relationship in JPA.
Meanwhile I was doing this in the User Table in Database:
USER_ID
USERNAME
USER_FRIENDS
And in the User Entity like this:
public class User
{
private Long userId;
private String username;
//Other fields;
#OneToMany(cascade = CascadeType.ALL)
#Column(name = "USER_FRIENDS")
private List<UserEntity> friends;
}
This doesn't work. So, how do I achieve this in JPA? Thanks in advance!
After doing research and help from #Florian Schaetz, I found the solution to the self referencing entities.
The need was User can have other User friends and that User can be friend to other Users. So, what I did was like this:
public class User
{
private Long userId;
private String username;
//Other fields;
#JoinTable(name = "USER_FRIENDS", joinColumns = {
#JoinColumn(name = "ADDING_USER", referencedColumnName = "USER_ID", nullable = false)}, inverseJoinColumns = {
#JoinColumn(name = "ADDED_USER", referencedColumnName = "USER_ID", nullable = false)})
#ManyToMany
private Collection<User> friends;
#ManyToMany(mappedBy = "friends")
private Collection<User> addUser;
}
Hope This will help other people! Thanks again friends!

Ignore an Entity fields for a Spring REST call

I have two Entity classes "Teacher & Class" where there is a #OneToMany relationship between them. The first one has a rest interface at /teachers/{id} and the second one has a rest interface at /classes/{id}. When a user sends a GET request to the Teacher interface, he should receive all of the Teacher and Class fields. But, when the user sends a GET request to the Class interface, I would like him to receive all of the Class fields and only a part of the Teacher fields "firstName, lastName"
Here are the entities code:
#Entity
#DiscriminatorValue("Th")
public class Teacher{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String firstName;
private String lastName;
private String phone;
#Column(unique = true)
#Email
private String email;
private String password;
#OneToMany(mappedBy = "teacher", fetch = FetchType.EAGER)
private List<Class> classes;
#OneToMany(mappedBy = "teacher", fetch = FetchType.EAGER)
private List<Note> notes;
protected Teacher() {
}
}
#Entity
public class Class {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
#OneToOne()
#JoinColumn(name = "subject_id")
private Subject subject;
#Enumerated(EnumType.STRING)
private Grade grade;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "teacher_id")
private Teacher teacher;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "class_student", joinColumns = { #JoinColumn(name = "class_id", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "student_id", referencedColumnName = "id") })
private List<Student> students;
protected Class() {
}
}
//getters and setters
Your request sounds mutualy exclusive, don't load Teacher object but do load it for it's ID.
You are better off then making the teacher object lazy load and then initialise it once class is loaded.
FYI
#JsonIgnore prevents loading of objects when RESTfull calls are made.

How to create join table with JPA annotations?

I need to create a join table in my database using JPA annotations so the result will be this:
So far I just implemented 2 entities:
#Entity
#Table(name="USERS", schema="ADMIN")
public class User implements Serializable {
private static final long serialVersionUID = -1244856316278032177L;
#Id
#Column(nullable = false)
private String userid;
#Column(nullable = false)
private String password;
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
#Entity
#Table(name="GROUPS", schema="ADMIN")
public class Group implements Serializable {
private static final long serialVersionUID = -7274308564659753174L;
#Id
#Column(nullable = false)
private String groupid;
public String getGroupid() {
return groupid;
}
public void setGroupid(String groupid) {
this.groupid = groupid;
}
}
Should i create another entity called USER_GROUP or i can just add some annotations, so the join table will be created automatically when i run create tables from entities(ORM)?
How should i annotate my entities to achieve the same as in the image?
You definitely shouldn't create User_Group entity as it's more the underlying database representation than the object oriented one.
You can achieve the join table by defining something like:
#Entity
#Table(name="USERS", schema="ADMIN")
public class User implements Serializable {
//...
#ManyToOne
#JoinTable(name="USER_GROUP")
Group group;
#Entity
#Table(name="GROUPS", schema="ADMIN")
public class Group implements Serializable {
//...
#OneToMany(mappedBy="group")
Set<User> users;
Edit: If you want to explicitly set the names of the columns you could use #JoinColumn elements as shown below:
#ManyToOne
#JoinTable(name="USER_GROUP",
joinColumns = #JoinColumn(name = "userid",
referencedColumnName = "userid"),
inverseJoinColumns = #JoinColumn(name = "groupid",
referencedColumnName = "groupid"))
Group group;
I would implement it this way:
#Entity
#Table(name="GROUPS", schema="ADMIN")
public class Group implements Serializable {
#OneToMany
#JoinTable(name = "USER_GROUP",
joinColumns = #JoinColumn(name = "groupid"),
inverseJoinColumns = #JoinColumn(name = "userid"))
private List<User> users;
}
Solution suggested by #PedroKowalski should work too, but then you'll have to keep a reference to Group entity in your User entity which is not always possible.
To have the same annotations like in your diagram you can do this in your User class:
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "USER_GROUP",
joinColumns = { #JoinColumn(name = "userid") },
inverseJoinColumns = { #JoinColumn(name = "groupid") })
private List<Group> grups;
in your group class
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "USER_GROUP",
joinColumns = { #JoinColumn(name = "groupid") },
inverseJoinColumns = { #JoinColumn(name = "userid") })
private List<User> users;
I'm wondering what is the point to create a Join Table in this way, considering that we can't access directly for queries?
JPA doesn't allow to make queries directly to the Join Table, so if the user want to do an operation on USER_GROUP, he has to creare a normal join query between users and groups; due to this, the join table USER_GROUP is useless.

Categories