Problem with saving data in ManyToMany tables, hibernate, spring - java

Below - parent table - users:
#Entity
#Table(name = "user")
public class User {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "username", length = 50, unique = true)
#NotNull
#Size(min = 4, max = 50)
private String username;
#Column(name = "password", length = 100)
#NotNull
#Size(min = 4, max = 100)
private String password;
#ManyToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
#JoinTable(
name = "user_role",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "role_id", referencedColumnName = "id")})
private List<Role> roles;
//constructor, getters/setters
Below You can find table with roles:
#Entity
#Table(name = "role")
public class Role {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name", length = 50)
#NotNull
#Enumerated(EnumType.STRING)
private RoleName name;
#ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
private List<User> users;
//constructor, getters/setters
And I will try save User by belows method:
private static SessionFactory sessionFactory;
private Session session;
#Override
public void saveUser(User user) {
Role role = getRoleByName(RoleName.ROLE_ADMIN);
user.getRoles().add(role );
role.getUsers().add( user );
session.persist(user);
}
public Role getRoleByName(RoleName name) {
Query query = session.createQuery("SELECT r FROM Role r WHERE r.name= :name");
query.setParameter("name", name);
return (Role) query.uniqueResult();
}
But I have two problems:
- first - the main problem - I did something wrong and I can't save new user.
- second one - I have null result in quer result in getRoleByName, but of course, that role exists in table user_roles.
And any solution will be perfect for me.
Thank you in advance.

Related

Spring data JPA one to Many / Many to one not inserting/updating details in database

Am doing one small activity of Teach and address relationship for one to many and in address block there will be one to one relationship between country, district, tahasil etc. Whenever am hitting api and to save it it's not updating or inserting Address in address table.
Detail is
#Entity
#Table(name = "teachers")
#PrimaryKeyJoinColumn(name = "user_id")
public class Teacher extends User {
#Size(min = 3, max = 50)
#Column(name = "first_name")
private String firstName;
#Size(min = 3, max = 50)
#Column(name = "middle_name")
private String middleName;
#Size(min = 3, max = 50)
#Column(name = "last_name")
private String lastName;
#OneToMany(fetch = FetchType.LAZY,mappedBy = "teacher")
#JsonManagedReference
private Set<Address> addresses = new HashSet<>(0);
Getter Setter...
}
Then Address Entity
#Entity
#Table(name = "address")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "address_id")
private Long addressId;
#ManyToOne (fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", nullable = false)
#JsonBackReference
private Teacher teacher;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "country_id", referencedColumnName = "country_id")
private Country country;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "state_id", referencedColumnName = "state_id")
private State state;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "district_id", referencedColumnName = "district_id")
private District district;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "tahasil_id", referencedColumnName = "tahasil_id")
private Tahasil tahasil;
#Column(name = "line_one")
private String lineOne;
#Column(name = "line_two")
private String lineTwo;
#Column(name = "landmark")
private String landmark;
#Column(name = "pincode")
private Integer pincode;
public Country getCountry() {
return country;
}
Other Getter Setter
The Country example same to state, district and tahasil
#Entity
#Table(name = "countries", uniqueConstraints = { #UniqueConstraint(columnNames = { "country_name" }) })
public class Country {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "country_id")
private Long countryId;
#NotBlank
#Size(min = 3, max = 50)
#Column(name = "country_name")
private String countryName;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "country")
private Address address;
Getter Setter
Finally in controller am doing like
Optional<Teacher> teacher = teacherRepo.findByUserId(id);
if (!teacher.isPresent())
return ResponseEntity.notFound().build();
teacher.get().setUserId(id);
teacher.get().setFirstName(teacherUpdateForm.getFirstName());
teacher.get().setMiddleName(teacherUpdateForm.getMiddleName());
teacher.get().setLastName(teacherUpdateForm.getLastName());
teacher.get().setAddresses(teacherUpdateForm.getAddresses());
userRepository.save(teacher.get());
Tried so may ways by referring multiple sites and readouts, but still not able to see any insert or update to address table. Please help me to get my mistake.
Regards,
Chetan
You need to cascade the persist of the Teacher entity.
Update the definition of the attribute Address inside the Teacher entity:
#OneToMany(fetch = FetchType.LAZY,mappedBy = "teacher", cascade = CascadeType.ALL)
#JsonManagedReference
private Set<Address> addresses = new HashSet();
You can play with the cascade type value as you want.

How should I get related entity?

I want to understand how to work with related entities in Hibernate.
There are two related entities:
#Entity
#Table(name = "usr")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String username;
#Column(nullable = false)
private String password;
#Column(nullable = false)
private String email;
private boolean active;
#Enumerated(EnumType.STRING)
private Role role;
#OneToMany(fetch = FetchType.LAZY,
mappedBy = "responsibleUser", cascade = CascadeType.ALL)
private List<GrowBox> growBoxes;
//def-constructor , getters, setters
}
and
#Entity
#Table(name = "growBoxes")
public class GrowBox {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#Column(nullable = false)
private Integer length;
#Column(nullable = false)
private Integer width;
#Column(nullable = false)
private Integer height;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "responsibleGrowBox", cascade = CascadeType.ALL)
private List<Plant> plants;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "activeGrowBox", cascade = CascadeType.ALL)
private List<Sensor> sensors;
#ManyToOne
#JoinColumn(name = "user_id")
private User responsibleUser;
//def-constructor , getters, setters
}
I have registered mapping using annotations. Hope it is correct. And I want to find box by user Id, but don't know how HQL query should be written. 'Cause there is no "user_id" field in my Box Class. Instead there is "User responsibleUser" field. And smth like this won't work(should not)
#Autowired
SessionFactory sessionFactory;
#Override
public List<GrowBox> findByUser(Long userId) {
Session session = sessionFactory.openSession();
String hqlQuery = "from GrowBox where user_id =: userId";
Query query = session.createQuery(hqlQuery);
List growBoxes = query.getResultList();
session.flush();
session.close();
return growBoxes;
}
A HQL query would be
String hqlQuery = "from GrowBox gb where gb.responsibleUser.id =: userId";

How do I prevent duplicate items in the cart?

For the current structure of database:
database structure
Users
#Entity
#Table(name = "users")
public class User {
#Id
#Column(name = "username", unique = true, nullable = false, length = 45)
private String username;
#Column(name = "password", nullable = false, length = 60)
private String password;
#Column(name = "enabled", nullable = false)
private boolean enabled;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "user", cascade=CascadeType.ALL)
private Set<UserRole> userRole = new HashSet<UserRole>(0);
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(
name = "users_product",
joinColumns ={#JoinColumn (name = "users_username", referencedColumnName = "username")},
inverseJoinColumns = {#JoinColumn(name = "Products_idProducts", referencedColumnName = "idProducts")}
)
List<Products> productsList = new ArrayList<Products>();
Products
#Entity
#Table(name = "products")
public class Products implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idProducts")
private long id;
#Column(name = "description")
private String description;
#Column(name = "price")
private String price;
#Column(name = "image")
private byte [] image;
#ManyToMany(mappedBy = "productsList")
List<User> usersList = new ArrayList<User>();
//setters - getters
I want to implement a shopping basket.
What I have now: A page with products and checkboxes on the view page. I find these products and send them to my controller, and afterwards set them to the current user.
productsList = myService.findManyProducts(toAdd);
user.setProductsList(productsList);
myService.updateUser(user);
#Transactional
public void updateUser(User user){
userDao.update(user);
}
update user function:
#Override
public void update(User user) {
entityManager.merge(user);
}
These actions are entered in the database as different values, depending on the latest additions.
What I want:
User adds some products to cart, browse other items, and add new products to the cart. How do I ensure that duplicate items are not found in the cart? Does JPA have some standard methods? Or do I need to check the product list by myself before adding them to the database?
I solved this by changing the List collection to a Set in the User entity.

How corectly select entity with ManyToMany realationship in Hibernate jpa

I have two tables(entities):
#Entity
#Table(name = "users")
#NamedQuery(name = "User.getAll", query = "SELECT c from User c")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#NotNull
#Column(name = "LOGIN")
private String login;
#Column(name = "PASSWORD", length = 64)
private String password;
#Column(name = "SALT", length = 80)
private String salt;
#ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
private Set<Role> roles;
#OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Permission> permissions;
And
#Entity
#Table(name = "roles")
#NamedQuery(name = "Role.getAll", query = "SELECT c from Role c")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "ROLE_NAME", length = 100)
private String roleName;
#ManyToMany(mappedBy = "roles")
private Set<User> users;
And method for select Users:
#Override
public List<User> getUsersList() {
Criteria criteria = getSession().createCriteria(User.class);
return (List<User>)criteria.list();
}
I have 2 users. First user has 2 roles and second user has 1 role.
But this method return me 3 users. User who has 2 role is dublicate.
Itried criteria.createCriteria("", JoinType.NONE);
but it not helped.
You need to use criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY), check:
criteria-distinct-root-entity-vs-projections-distinct

JPA 2.0 CriteriaQuery on tables in #ManyToMany with JoinTable and Lazy Fetch

I have two entities in a #ManyToMany relationship like this:
#Entity
#Table(name = "USERS")
public class User implements EntityMetaModel, Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Integer id;
#Column(name = "USERNAME", unique = true, length = 20)
private String username;
#Column(name = "PASSWORD", nullable = false, length = 32)
private String password;
#Column(name = "ENABLED")
private Boolean enabled;
#ManyToMany(
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
fetch = (FetchType.LAZY)
)
#JoinTable(
name = "USER_ROLES",
joinColumns = #JoinColumn(name="USERID", referencedColumnName="ID"),
inverseJoinColumns = #JoinColumn(name="ROLEID", referencedColumnName="ID")
)
#SequenceGenerator(
name = "sgIdUserRoles",
sequenceName = "SQ_ID_USER_ROLES"
)
#CollectionId(
columns = {#Column(name="ID")},
type = #Type(type="integer"),
generator = "sgIdUserRoles"
)
#Fetch(value = FetchMode.SELECT)
private Collection<Role> roles = new HashSet<Role>();
}
#Entity
#Table(name = "ROLES")
public class Role implements EntityMetaModel, Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Integer id;
#Column(name = "ROLENAME", unique = true, length = 50)
private String rolename;
#ManyToMany(
cascade = {CascadeType.PERSIST, CascadeType.MERGE},
fetch = (FetchType.LAZY)
)
#JoinTable(
name = "USER_ROLES",
joinColumns = #JoinColumn(name="ROLEID", referencedColumnName="ID"),
inverseJoinColumns = #JoinColumn(name="USERID", referencedColumnName="ID")
)
#SequenceGenerator(
name = "sgIdUserRoles",
sequenceName = "SQ_ID_USER_ROLES"
)
#CollectionId(
columns = {#Column(name="ID")},
type = #Type(type="integer"),
generator = "sgIdUserRoles"
)
#Fetch(value = FetchMode.SELECT)
private Collection<User> users = new HashSet<User>();
}
I've created the metamodel:
#StaticMetamodel(User.class)
public class User_ {
public static volatile SingularAttribute<User, Integer> id;
public static volatile SingularAttribute<User, String> username;
public static volatile SingularAttribute<User, String> password;
public static volatile SingularAttribute<User, Boolean> enabled;
public static volatile CollectionAttribute<User, Role> roles;
}
#StaticMetamodel(Role.class)
public class Role_ {
public static volatile SingularAttribute<Role, Integer> id;
public static volatile SingularAttribute<Role, String> rolename;
public static volatile CollectionAttribute<Role, User> users;
}
Class User has a Collection of Role. What I need to do from JPA2 CriteriaQuery is to find the Roles that havent an User given by id.
How can I do a CriteriaQuery like this?
select r.id, r.rolename
from roles r
where not exists
(select 1
from user_roles ur
where ur.roleid = r.id
and ur.userid = :userid)
If a query is:
List<Role> roles = session.createQuery("select u.roles from User u left join fetch u.roles where u.id= :idParam").
setParameter("idParam", param).
asList();
the following criteria should work, as I remember:
List<Role> roles = session.
createCriteria(Role.class).
add(Restrictions.eq("users.id", param)).
setFetchMode("users", FethchMode.EAGER).
list();
Otherwise, you return a query with a non-entity structure, you may need a ResultTransformer.

Categories