OneToOne with hibernate JPA - java

I'm trying to relate two tables
User and Address
A user has a single address, an address belongs to only one user. Keys are listed by the ID of an Address
so I create my address first and then I create a user and link it with an address id
But I can't do it at all, I have the following error in return:
Error creating bean with name 'entityManagerFactory' defined in class path resource [org / springframework / boot / autoconfigure / orm / jpa / HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is java.lang.NullPointerException: Cannot invoke "org.hibernate.mapping.PersistentClass.getTable ()" because "classMapping" is null
i'm totally new to hibernate but i need this project for college so forgive me for the ignorance on the subject
Thats my code:
USER/USUARIO Class:
import org.hibernate.validator.constraints.br.CPF;
import javax.persistence.*;
import javax.validation.constraints.*;
public class Usuario{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column
#NotNull
#Size(min = 5,max = 30)
#Pattern(regexp = "^[a-zA-Z\s]*$", message = "Nome inválido! Digite apenas letras e espaçamento") //Permite apenas letras e espaço
private String nome;
#NotNull
#CPF
private String cpf;
#NotNull
#Email
private String email;
#NotNull
#Size(min = 5,max = 12)
private String senha;
private Integer telefone;
#DecimalMin("0")
#DecimalMax("5")
private Double avaliacao;
#NotNull
#OneToOne(cascade = CascadeType.ALL,mappedBy = "id")
private Endereco endereco;
//Atributos para usuários autônomos
private Boolean isAutonomo;
private String categoriaAutonomo;
private Double precoAutonomo;
//Getters and Setters
ADRESS/ENDERECO Class
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
#Entity
#Table(name = "endereco")
public class Endereco {
#Id
#OneToOne
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#NotNull
#Size(min = 8,max = 8)
private String cep;
#NotNull
private String bairro;
#NotNull
private String logradouro;
#NotNull
private Integer numeroLogradouro;
private String complemento;
#NotNull
#Size(min = 2,max = 2)
private String uf;
#NotNull
private String cidade;
CONTROLLER
import br.com.bandtec.projetocaputeam.dominio.*;
import br.com.bandtec.projetocaputeam.repository.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
#RestController
#RequestMapping("/caputeam")
public class CaputeamController {
#Autowired
private UsuariosRepository usuariosRepository;
#Autowired
private EnderecoRepository enderecoRepository;
//--- USERS
#GetMapping("/usuarios")
public ResponseEntity getUsuarios(){
List<Usuario> usuarios = usuariosRepository.findAll();
return !usuarios.isEmpty() ? ResponseEntity.status(200).body(usuarios) :
ResponseEntity.status(204).build();
}
#PostMapping("/cadastrar-usuario")
public ResponseEntity cadastrarUsuario(#RequestBody #Valid Usuario novoUsuario){
usuariosRepository.save(novoUsuario);
return ResponseEntity.ok().build();
}
//--- ADRESS
#PostMapping("/cadastrar-endereco")
public ResponseEntity cadastrarEndereco(#RequestBody #Valid Endereco novoEndereco){
enderecoRepository.save(novoEndereco);
return ResponseEntity.ok().build();
}
}
APPLICATION
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class ProjetoCaputeamApplication {
public static void main(String[] args) {
SpringApplication.run(ProjetoCaputeamApplication.class, args);
}
}
And thats my Logic Model
EDIT
I tried to delete the "mapped by" part and remove the #OneToOne from Address but now it returns the following error when I try to send an POST of Adress:
org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Referential integrity constraint violation: "FKMXNOON0IKGA83W1A203Y6OFPN: PUBLIC.ENDERECO FOREIGN KEY(ID) REFERENCES PUBLIC.USUARIO(ID) (1)"; SQL statement:
insert into endereco (bairro, cep, cidade, complemento, logradouro, numero_logradouro, uf, id) values (?, ?, ?, ?, ?, ?, ?, ?) [23506-200]
as if he didn’t enter any Address fields
Im sending my POST by Postman like this:
{
"bairro": "Vila Prmavera",
"cep": "03388110",
"cidade": "São Paulo",
"complemento": "b1",
"logradouro": "Rua das dores",
"numeroLogradouro": 7,
"uf": "SP"
}

Don't map on the Id. Map means entity mapping not id mapping.
public class Endereco {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#OneToOne
private Usuario usuario
....
}
Or if you don't want Endereco to hold a reference to a Usuario just remove it. But you can't place #OneToOne on the id field. If you have only on one side the #OneToOne then you need also the annotation #MapsId.
public class Usario {
#NotNull
#MapsId
#OneToOne(cascade = CascadeType.ALL)
private Endereco endereco;
public class Endereco {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id
}
Because #OneToOne tries to Map with an entity which means to a table in Database. For id there isn't any entity or Table in the database. That is why it complains

Related

Why Doesn't jpa add data to the foreign key value

I have a users table which contains the user details. i also have a authorities table which has the role of a user. The user and authorities table has one to many mapping. When i try to save the details using Jpa the foreign key column is blank no data is inserted in that field. i have a form in which i am specifying the role of the user along with other details.
package com.example.StarsProject.Model;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
#Entity
#Table
#Getter
#Setter
public class Authorities {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String role;
#ManyToOne(cascade = CascadeType.PERSIST,fetch=FetchType.EAGER)
#JoinColumn(name = "users_id", referencedColumnName = "id")
private Users users;
public Authorities(String role){
this.role = role;
}
}
package com.example.StarsProject.Model;
import com.example.StarsProject.DTO.UserDTO;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table
#Getter
#Setter
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "first_name")
private String firstname;
#Column(name = "last_name")
private String lastname;
#Column(unique = true)
private String email;
private String password;
#OneToMany(fetch = FetchType.EAGER,targetEntity = Authorities.class,mappedBy = "users", cascade = CascadeType.PERSIST)
private Set<Authorities> authorities;
public Users(UserDTO userDTO) {
this.email = userDTO.getEmail();
this.firstname = userDTO.getFirstname();
this.lastname = userDTO.getLastname();
this.password = userDTO.getPassword();
// Authorities authorities = new Authorities();
// authorities.setRole(userDTO.getRole());
// Set<Authorities> set = new HashSet<>();
// set.add(authorities);
this.authorities = new HashSet<Authorities>(Arrays.asList(new Authorities(userDTO.getRole())));
}
}
package com.example.StarsProject.Service;
import com.example.StarsProject.DTO.UserDTO;
import com.example.StarsProject.Model.Users;
import com.example.StarsProject.Repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class UserDetailsServiceImpl implements UserDetailsServiceInterface{
#Autowired
UserRepository userRepository;
#Override
public void storeUserDetails(UserDTO userDTO) {
Users users = new Users(userDTO);
userRepository.save(users);
}
}
When i try to save the user details it doesn't insert any value in the foreign key column. Can someone tell me what i am doing wrong.
You need to setusers field in Authorities manually. Hibernate won't fill it for you.

Spring Boot Jpa mapping

I am learning spring boot data JPA.
Here is my code
Users.java
#Entity
#Table(name = "user_Details")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
private Integer id;
#Column(name = "name")
private String name;
#Column(name = "password")
private String password;
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="user_id", referencedColumnName="user_id")
private Set<usersAction> usersAction;
usersAction.java
#Entity
#Table(name="user_Action")
public class usersAction {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="action_id")
private Integer Action_id;
#Column(name="user_id")
private Integer id;
#Column(name="users_Role")
private String usersRole;
UsersRepository.java
package com.demo.repository;
import java.util.Set;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import com.demo.model.Users;
#Repository
public interface UsersRepository extends JpaRepository<Users, Integer> {
#Query(value="select u.password,u.user_id,u.name,ua.users_Role from user_details as u"
+ " inner join user_action as ua"
+ " on u.user_id=ua.user_id",nativeQuery=true)
Set<Users> findById();
}
UsersController.java
#RestController
#RequestMapping("/users")
public class usersController {
#Autowired
UsersRepository usersRepository;
#GetMapping("/all")
public List<Users> getAll() {
return usersRepository.findAll();
}
#RequestMapping("/byid")
public Set<Users> findByName()
{
Set<Users> obj1=usersRepository.findById();
return obj1;
}
}
When I am accessing this http://localhost:8080/users/byid
I am getting output as id ,name ,password from users_details table and also Action_id,id and users_role from users_Action
But I am expecting in Result only name from users_detail and usersRole from users_Action table
What i need to change for that?
You need to create interfaces like this
interface UsersSummary {
String getName();
String getName();
UsersActionSummary getUsersAction();
interface UsersActionSummary {
String getUsersRole();
Integer getId();
Integer getAction_Id();
}
}
And then change your repository method to return this
#Query(value="select u.password,u.user_id,u.name,ua.users_Role from user_details as u"
+ " inner join user_action as ua"
+ " on u.user_id=ua.user_id",nativeQuery=true)
Collection<UsersSummary> findById();

How to create a model, in Spring, from json where the foreign key is referenced as a long attribute?

One Group has many Users:
Group
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.*;
import java.util.Collection;
import java.util.List;
#Entity
#Table(name = "GROUPS")
public class Group {
#Id
#Column(name = "ID")
private Long ID;
#Column(name = "NAME")
private String NAME;
//#JsonManagedReference
#OneToMany(mappedBy = "group"
//, fetch = FetchType.EAGER
//, cascade = CascadeType.ALL
)
private List<Users> itsUser;
//getters and setters are omitted for clarity
}
Users
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.persistence.*;
import static javax.persistence.GenerationType.SEQUENCE;
#Entity
#Table(name = "USERS")
#SequenceGenerator(name = "SEQUENCE_USER_ID", //my own name in java (unique)
sequenceName = "GENERATOR_SEQUENCE_USERS", //in database
initialValue = 1,
allocationSize = 1)
public class Users {
#JsonProperty(value = "id") //these play a role when both reading or writing
#Id
#Column(name = "ID")
#GeneratedValue(strategy=SEQUENCE, generator="SEQUENCE_USER_ID")
private Long ID;
#JsonProperty(value = "name")
#Column(name="NAME")
private String NAME;
#JsonProperty(value = "username")
#Column(name="USERNAME")
private String USERNAME;
#JsonProperty(value = "password")
#Column(name="PASSWORD")
private String PASSWORD;
#JsonProperty(value = "email")
#Column(name="EMAIL")
private String EMAIL;
#JsonProperty(value = "picture") //Now it works with both mypic and picture as json keys
#Column(name="PICTURE")
private String PICTURE;
//#Column(name="GROUP_ID") //we already have a ManyToOne for this, we cannot repeat it
#JsonProperty(value = "groups_id")
//to ignore it in jpa (http://stackoverflow.com/questions/1281952/jpa-fastest-way-to-ignore-a-field-during-persistence)
private Long itsGroupId;
#Transient
public Long getItsGroupId() {
if(itsGroupId == null) {
this.itsGroupId = group.getID();
} else {
//nop
}
return itsGroupId;
}
public void setItsGroupId(Long itsGroupId) {
this.itsGroupId = itsGroupId;
}
//#JsonIgnore
//#JsonProperty(value = "groups_id")
//#JsonBackReference
#ManyToOne(optional = false, targetEntity = Group.class)
#JoinColumn(
name = "GROUP_ID", //column name
referencedColumnName = "ID" //reference name
)
private Group group;
//getters and setters are omitted for clarity
}
We are using Spring with Spring-data and Jackson to do things automagically but we cannot configure the magic:
We are trying to stick on the following constraints at the same time:
1) Keep the ability to have a reference to the groupId and the ManyToOne relationship group.
This is easy to be achieved by putting #Transient annotation at the groupId because #Column is not allowed since we have already declared the #ManyToOne annotation. You also have to implement the getGroupId method accordingly.
2) Return a json of Users class that contains the groups_id.
This can be implemented by setting the #JsonProperty annotation.
3) Create a user class, and also save it in the database, by a json. The json contains groups_id which has as a value an integer for the foreign key.
This does not work because by setting it #Transient above, then the system refuses to save in the database something that is transient or at least this is how we interpret this exception:
HTTP Status 500 - Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: not-null
property references a null or transient value: com.pligor.mvctest.models.Users.group;
nested exception is org.hibernate.PropertyValueException:
not-null property references a null or transient value: com.pligor.mvctest.models.Users.group
On the backend do something like this:
Group group = groupRepository.findById(userResource.getGroupId());
if (group != null) {
User user = new User(userResource);
user.setGroup(group);
userRepository.save();
}
The idea behind this is that you need to fetch the group from the DB, to be able to link it with the newly created User

How to join three entities in one table using spring jpa?

I am trying to join three entities (table) using spring-jpa into one table using Many-To-Many relationship.
Three classes are :
1] User
2] Resource
3] Privilege
And I want to combine these three entities into one User_Resource_Privilege table
User Entity
package com.****.acl.domain;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
#Entity
public class User {
#Id #GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
#Column(name="user_id", nullable=false, length=40)
private String userId;
#Column(name="user_name", nullable=false, length=45)
private String userName;
#Column(name="first_name", nullable=true, length=45)
private String firstName;
#Column(name="last_name", nullable=true, length=45)
private String lastName;
#Column(name="email", nullable=true, length=50)
private String email;
public User(){
}
public User(String userName, String firstName, String lastName, String email) {
this.userName = userName;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
getter and setters .......
}
Resource Entity
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.*;
import org.hibernate.annotations.GenericGenerator;
#Entity
public class Resource {
#Id #GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
#Column(name="resource_id", nullable=false, length=40)
private String resourceId;
#Column(name="resource_name", nullable=false, length=45)
private String name;
#Column(name="resource_type", nullable=false, length=45)
private String type;
public Resource(){
}
public Resource(String name, String type) {
this.name = name;
this.type = type;
}
getter and setter ......
}
Privilege Entity
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.*;
import org.hibernate.annotations.GenericGenerator;
#Entity
public class Privilege {
#Id #GeneratedValue(generator="system-uuid")
#GenericGenerator(name="system-uuid", strategy = "uuid")
#Column(name="privilege_id", nullable=false, length=40)
private String privilegeId;
#Column(name="resource_name", nullable=false, length=45)
private String name;
#Column(name="resource_description", nullable=true, length=45)
private String description;
public Privilege(){
}
getters and setters ....
}
Now I want to create one table by joining all the three entities described above.
The join in ER diagram:
Can someone please help me in joining these three tables using Many-To-Many relationship and let me know how to achieve this using spring-jpa and REST ?
Also it will be great if you please explain how to insert data in this "User_Resource_Privilege" table using REST/curl command ?
What you could do is make an embeddable ID and wrap it with the class. You can afterwards even expand this wrapper class to hold other fields.
java geeks example of embedded id
You would get something like
#Embeddable
public class EmbeddedIdClass implements Serializable {
private String userId;
private String resourceId;
private String privilegeId;
// constructors, getters and setters, equals, etc
}
#Entity
public class Wrapper {
#EmbeddedId
private EmbeddedIdClass id;
// constructors, etc
}
Instead of just using the strings in this example, you should use the complete objects and let hibernate (or something like it) do it's stuff. It should only take the id's into the database and do it's magic itself.
edit:
Just wanting to insert the id's as values, but keeping relationships would look something like this
#Entity
public class Wrapper {
#Id
private String id;
private User user;
private Resource resource;
private Privilege privilege;
// constructors
public Wrapper(final User user, final Resource resource, final Privilege privilege) {
this.user = user;
this.resource = resource;
this.privilege = privilege;
}
}

Mapped foreign key in Hibernate Entity

Hi write Spring application, using Spring Security. It's my database for user and account role:
create table users (
id int not null primary key,
username varchar2(20) not null unique,
password varchar2(20) not null,
firstName varchar2(20),
lastName varchar2(20),
personalId varchar2(11) unique,
city varchar2(40),
address varchar2(40),
email varchar2(30) unique,
phone varchar2(9) unique,
enabled number(1) not null
);
create table user_roles (
id int primary key,
name varchar2(20) not null,
username varchar(20) constraint username_fk references users(username) not null
);
My Entity classes:
#Entity
#Table(name = "users")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "id")
private Integer id;
#NotNull
#Column(name = "username")
private String username;
#NotNull
#Column(name = "password")
private String password;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#Column(name = "personalId")
private String personalId;
#Column(name = "city")
private String city;
#Column(name = "address")
private String address;
#Column(name = "email")
private String email;
#Column(name = "phone")
private String phone;
#NotNull
#Column(name = "enabled")
private int enabled;
#OneToMany(mappedBy = "username")
private Set<UserRole> userRoleSet = new HashSet<UserRole>(0);
#Entity
#Table(name = "user_roles")
public class UserRole implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name = "id")
private Integer id;
#NotNull
#Column(name = "name")
private String name;
#JoinColumn(name = "username")
#ManyToOne(targetEntity = User.class)
private String username;
When I try login in my system i have error:
Hibernate: select userrolese0_.username as username3_1_0_, userrolese0_.id as id1_0_0_, userrolese0_.id as id1_0_1_, userrolese0_.name as name2_0_1_, userrolese0_.username as username3_0_1_ from user_roles userrolese0_ where userrolese0_.username=?
WARN : org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 1722, SQLState: 42000
ERROR: org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ORA-01722: invalid number
My class implements UserDetailsService:
package pl.piotr.ibank.service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pl.piotr.ibank.daointerface.UserDao;
import pl.piotr.ibank.model.UserRole;
#Transactional(readOnly = true)
#Service("userDetailsService")
public class MyUserDetailsService implements UserDetailsService {
#Autowired
UserDao userDao;
#Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
pl.piotr.ibank.model.User user = userDao.findByUsername(username);
List<GrantedAuthority> authorities = buildUserAuthority(user
.getUserRole());
return buildUserForAuthentication(user, authorities);
}
private List<GrantedAuthority> buildUserAuthority(Set<UserRole> userRoles) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
for (UserRole userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getName()));
}
List<GrantedAuthority> result = new ArrayList<GrantedAuthority>(
setAuths);
return result;
}
private UserDetails buildUserForAuthentication(
pl.piotr.ibank.model.User user, List<GrantedAuthority> authorities) {
return new User(user.getUsername(), user.getPassword(), true, true,
true, true, authorities);
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
I think so, my mapped foregin key for tables is bad. Example query from Userreturn users from table, but when i try get user_roles i have above error. Please check correctness my mapped. I using Oracle database and Hiberante.
The problem is, that when you're mapping entities Hibernate expects the foreign key to be the id of the referenced entity, i.e. you should map on user-id instead of username.
Also your entity mapping seems to be wrong: you use a ManyToOne with the target entity being User but the type of the property is String. AFAIK Hibernate would try to assign the user to username, which should fail miserably.
So the table should look like this:
create table user_roles (
id int primary key,
name varchar2(20) not null,
userid int constraint userid_fk references users(id) not null
);
And the mapping in UserRole should then be:
#JoinColumn(name = "userid")
#ManyToOne
private User user;
Plus the reverse mapping in User:
#OneToMany(mappedBy = "user")
private Set<UserRole> userRoleSet;
As a side note, please keep in mind that id is a special keyword in HQL, i.e. it will always reference an entity's id. If id always is the only property annotated with #Id then it's no problem, but if you change that you can run into problems with queries selecting the wrong data or even failing.

Categories