I've created a class User (Usuario) and I need to do a relationship with the class Rules, but I'm facing a problem about relationship:
My class User (Usuario):
#Entity
public class Usuario implements UserDetails {
private static final long serialVersionUID = 1L;
#Id
private String email;
private String senha;
#OneToMany(fetch=FetchType.EAGER)
private List<Role> roles = new ArrayList<Role>();
//there are getters, setters and methods of UserDetails
Class Role:
#Entity
public class Role implements GrantedAuthority {
private static final long serialVersionUID = 1L;
#Id
private String nome;
//private TipoRole nome;
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
#Override
public String getAuthority() {
// TODO Auto-generated method stub
return this.nome;
}
}
I've inserted the roles ROLE_ADMIN and ROLE_USER in the entity Role, but the database is not allowing more than one user per role
By default, all users created in the system are RULE_USER, but it works only in the first time:
first time ok
Nevertheless, in the next time, the database doesn't allow to record a new user:
I've tried even using sql command:
insert into usuario_roles(Usuario_email, nome) values ('user#test.com', 'ROLE_USER');
Error message: 11:42:27 insert into usuario_roles(Usuario_email, nome) values ('user#test.com', 'ROLE_USER') Error Code: 1452. Cannot add or update a child row: a foreign key constraint fails (mvpnfinance.usuario_roles, CONSTRAINT FK_j30w68qri0gjgp8irgyf68kdd FOREIGN KEY (Usuario_email) REFERENCES usuario (email)) 0.125 sec
error sql
UPDATE
I've changed the relationship to #ManyToMany, if I insert directly into the database is working well. But in the application I'm facing other problem.
HTTP Status 500 - Request processing failed; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'ROLE_USER' for key 'PRIMARY'
I don't know why, but when I'm saving a new Person, the system tries to insert a new ROLE_USER in the table Role.
I'found this sequence that is causing this error, in my Controller class:
List<Role> roles = new ArrayList<Role>();
Role role = new Role();
role.setNome("ROLE_USER");
roles.add(role);
usuario.setRoles(roles);
If I remove these lines, the system doesn't record the role into the ManyToMany table.
Related
There are two problems that I do not understand.
First, the error message on the console. It does not give me the whole error message. Therefore I do not understand the issue at all :S The IDE is STS.
Second, why do I get this error, "JsonMapping failed to lazily initialize a..."
#Test
public void testUpdateCar() throws Exception {
Car car = carRepository.findById(new Long(1)).get();
car.setBrand("Mazda");
car.setModel("326");
String putJSON = objectMapper.writeValueAsString(car);
mockMVC.perform(MockMvcRequestBuilders.put(String.format("/api/cars/%d", car.getId())).contentType(MediaType.APPLICATION_JSON_UTF8).content(putJSON))
.andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isCreated())
.andExpect(MockMvcResultMatchers.content().contentType("application/hal+json;charset=UTF-8"));
}
Car:
#Entity
public class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToOne
private User owner;
private String brand;
private String model;
private String color;
private String plate;
private String additionals;
Update 1:
The error itself:
com.fasterxml.jackson.databind.JsonMappingException: failed to lazily
initialize a collection of role:
me.eraytuncer.carpool.entity.User.carList, could not initialize proxy
- no Session (through reference chain: me.eraytuncer.carpool.entity.Car["owner"]->me.eraytuncer.carpool.entity.User["carList"])
Update 2:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String phone;
private String email;
#OneToMany(cascade = CascadeType.REMOVE, mappedBy = "owner")
private List<Car> carList;
Update 3:
#PutMapping("/cars/{id}")
ResponseEntity<?> replaceCar(#RequestBody Car newCar, #PathVariable Long id) {
if (repository.existsById(id)) {
newCar.setId(id);
Resource<Car> carResource = assembler.toResource(repository.save(newCar));
try {
return ResponseEntity
.created(new URI(carResource.getId().expand().getHref()))
.body(carResource);
} catch (URISyntaxException e) {
e.printStackTrace();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
} else {
throw new CarNotFoundException(id);
}
}
Update 4:
Adding #JsonIgnore solved the issue somehow. Maybe it was a misleading issue caused by infinite recursion?
Looks like field
private List<Car> carList;
is resolved lazily (default fetch type in #OneToMany), which means it is populated from DB only when getter for this field is called. In your case it is called by Jackson serializer outside scope of the Hibernate session and property cannot be populated. Changing fetch type to EAGER in #OneToMany on carList property should help.
Also consider using DTO pattern, because returning entities from API is considered as bad practice.
You have mapped #OneToOne against #OneToMany. It should be #ManyToOne on the owning side:
#ManyToOne
#JoinColumn(name = "user_id") // if needed
private User owner;
I faced the same issue and it got resolved by using #Transactional on the method. #Transactional help to keep open the session so that lazy collection could be fetched.
I have problem with adding records to my junction table with JPA+Hibernate
when I try to add simple record with POST request it's throws me an error:
"message": "could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement"
And in my console:
MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails*
I had defined Join columns #JoinColumn(insertable=false, updatable=false) because it was demanding by Hibernate, otherwise it throws me an error that I should do that...
Here is my junction entity code:
#Entity
#Table(name = "hospital_doctor")
#IdClass(Hosdoc.class)
public class HospitalDoctor implements Serializable {
#Id
private int hospitalId;
#Id
private int doctorId;
// fields of hospitalDoctor table
#Temporal(TemporalType.DATE)
private Date contractStartDate;
#Temporal(TemporalType.DATE)
private Date contractEndDate;
private String position;
private String supervisor;
private boolean partTime;
#ManyToOne
#JoinColumn(name="HospitalId", insertable = false, updatable = false)
private Hospital hospital;
#ManyToOne
#JoinColumn(name="DoctorId", insertable = false, updatable = false)
private Doctor doctor;
// GETTERS AND SETTERS....
I wrote simple adding function in hospital class but I don't know how to use it to add record to junction table by POST request.
public void addDoctor(Doctor doctor, boolean partTime, Date contractEndDate, Date contractStartDate,
String position, String supervisor) {
HospitalDoctor association = new HospitalDoctor();
association.setDoctor(doctor);
association.setHospital(this);
association.setDoctorId(doctor.getId());
association.setHospitalId(this.getId());
association.setContractStartDate(contractStartDate);
association.setContractEndDate(contractEndDate);
association.setPosition(position);
association.setSupervisor(supervisor);
association.setPartTime(partTime);
doctors.add(association);
}
Service:
public void addHospitalDoctor(HospitalDoctor hospitalDoctor) {
hospitalDoctorDao.save(hospitalDoctor);
}
Controller:
#PostMapping(value = "/api/hospitaldoctors")
public void addHospitalDoctor(HospitalDoctor hospitalDoctor) {
hospitalDoctorService.addHospitalDoctor(hospitalDoctor);
}
I have an application which was running on H2 database and Hibernate is the ORM tool. Currently, I am changing this application to use mysql database instead of H2 database and while doing this I came to this issue when saving flagjp entity.
Here is the FlagJP entity that caused this issue.
#Entity
public class FlagJP extends BaseModelJP {
#Id
#GeneratedValue(generator = "IdOrGenerated")
#GenericGenerator(name = "IdOrGenerated", strategy = "com.jp.menu.api.model.JPSequenceGenerator")
private Long flagId;
private String flagKey;
#OneToMany(mappedBy="flag", cascade = CascadeType.ALL)
private List<FlagLangJP> flagLangs = new ArrayList<>();
#ManyToOne
private FlagCategoryJP flagCategory;
Here are the related entities for the FlagJP
Second entity
#Entity
public class FlagLangJP extends BaseModelJP {
#Id
#GeneratedValue(generator = "IdOrGenerated")
#GenericGenerator(name = "IdOrGenerated", strategy = "com.jp.menu.api.model.JPSequenceGenerator")
private Long id;
private String languageCode;
private String flagName;
private String flagDescription;
#ManyToOne
private FlagJP flag;
Third Entity
#Entity
public class FlagCategoryJP extends BaseModelJP {
#Id
#GeneratedValue(generator = "IdOrGenerated")
#GenericGenerator(name = "IdOrGenerated", strategy = "com.jp.menu.api.model.JPSequenceGenerator")
private Long flagCategoryId;
private String flagCategoryName;
#OneToMany(mappedBy = "flagCategory")
private List<FlagJP> flags;
While looking into this issue, I was able to figure out that this is cased by FlagJP table schema not having auto increment set in the database when hibernate generated the DDL.
here is the DDL of FlagJP
If I try to manually set the auto increment by executing a sql query, then mysql throw this error.
Operation failed: There was an error while applying the SQL script to the database.
ERROR 1833: Cannot change column 'flagId': used in a foreign key constraint 'FK_sk95esyf1n0gt1qqmlmdmq0uw' of table 'butterfly_emenu.flaglangbpa'
SQL Statement:
my question is , this problem does not happen when using H2 database. how to solve this issue using hibernate when the database is mysql.
Thanks in advance for any advice
Update:
Here is the code for sequence generator I am using
public class JPSequenceGenerator extends IdentityGenerator {
private static final Logger logger = LoggerFactory.getLogger(JPSequenceGenerator.class);
#Override
public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
Serializable id = session.getEntityPersister(null, object).getClassMetadata().getIdentifier(object, session);
if (id == null) {
id = super.generate(session, object);
}
return id;
}
}
Try below code with auto_increment field ID in mysql
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long flagId;
If you are not able to add auto_increment for flagId then remove the foreignKey FK_sk95esyf1n0gt1qqmlmdmq0uw then add auto_increment and add foreign key again
I am using Spring and MySql database. I am trying to delete user from users table which is connected to post table as one to many relationship.
User.java
#OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
private List<Post> posts;
//getters and setters
}
Post.java
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn (name="profesor_id", referencedColumnName="id", unique=true)
private User user;
//getters and setters
Profesor.java
#Entity
public class Profesor extends User {
private String jobTitle;
public String getJobTitle() {
return jobTitle;
}
public void setJobTitle(String jobTitle) {
this.jobTitle = jobTitle;
}
}
Controller.java
#RequestMapping(value="profesorList/{id}/deleteProfesor", method=RequestMethod.GET)
public ModelAndView deleteProfesor(#PathVariable long id){
profesorRepository.delete(id);
return new ModelAndView("redirect:/profesorList");
}
index.html
<td><a th:href="#{'/profesorList/{id}/deleteProfesor'(id=${profesor.id})}"</a></td>
UserRepository.java
#Repository
public interface UserRepository extends CrudRepository<User, Long>, UserDetailsService {
public User findUserByUsername(String username);
}
ProfesorRepository.java
#Repository
public interface ProfesorRepository extends JpaRepository<Profesor, Long>{
}
I am using one table inheritance. So I have user and profesor in same table as users.
But when I try to execute it I am getting this error:
Cannot delete or update a parent row: a foreign key constraint fails (`data`.`post`, CONSTRAINT `FK5q2menkhkd7av4xfslbgbuq3y` FOREIGN KEY (`profesor_id`) REFERENCES `users` (`id`))
How can I solve it?
you have a bidirectional relation, so if you are planning to remove an entity you need to remove the relation (otherwise you need to cascade your delete) so if you want to remove a Post, you need to get the user and remove this post from the post list in that user before deleting the post
Add "CascadeType.REMOVE" in the User model as given below.
#OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE })
private List<Post> posts;
//getters and setters
}
To delete the user table entry, first have to delete the child table 'post' entry for this record.
#RequestMapping(value="profesorList/{id}/deleteProfesor", method=RequestMethod.GET)
public ModelAndView deleteProfesor(#PathVariable long id){
Profesor profesor = profesorRepository.findOne(id);
if(Objects.nonNull(profesor)){
List<Post> posts = profesor.getPosts();
for (Iterator<Post> iterator = posts.iterator(); iterator.hasNext();) {
Post post = iterator.next();
post.setUser(null)
iterator.remove(); //remove the child first
}
profesorRepository.delete(profesor);
}
return new ModelAndView("redirect:/profesorList");
}
I create 3 model classes in playframework, and set one-one relationship and one-to many relationship in one of the class. The code snippet are as follows:
Person.java
///////////////////////
#Entity
#Table(name = "person")
public class Person extends Model{
#Id
private Long id;
private String lastName;
private String firstName;
private String userId;
private Address address;
private List<Task> tasks;
....
}
Task.java
//////////////////////////
#Entity
#Table(name = "task")
public class Task extends Model{
#Id
private Long id;
private String name;
private String descript;
private String details;
...........
}
Address.java
////////////////////
#Entity
#Table(name = "address")
public class Address extends Model{
#Id
private Long id;
private String street;
private String state;
.........
}
I create person object and set the attributes/one-one/one-many relationships.
I try to save the person object with both attributes and relationships to mysql db by calling person.save().However, it ends up saving only attributes userId/firstName/LastName. the address object and tasks list object are not saved in db.
My question is : is there any way to save the relationship objects in db long with person.save()? that is , after calling person.save(), address table and task table create new entires corresponding to them.
I end up setting foreign keys in person class to handle this relationship manually.
Thanks in advance!
You might want to have a look at a JPA tutorial in particular topics about #OneToMany and #OneToOne annotations. I'd recommend https://en.wikibooks.org/wiki/Java_Persistence/OneToMany and https://en.wikibooks.org/wiki/Java_Persistence/OneToOne.