Adding records to junction table JPA - mysql

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);
}

Related

(Hibernate, mysql) Caused by: java.sql.SQLException: Field 'id' doesn't have a default value

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

Relationship between User and Roles Spring Security

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.

#MapsId and two objects with the same identifier value associated with the session

I have #OneToOne relationship between my entities DirigeantsEntreprise and Fournisseur like this :
#Entity
#Table(name = "dirigeants_entreprise", catalog = "ao")
public class DirigeantsEntreprise implements java.io.Serializable {
private int idEntreprise;
private Fournisseur fournisseur;
private String nom;
private String poste;
....
#Id
#Column(name = "id_entreprise", unique = true, nullable = false)
public int getIdEntreprise() {
return this.idEntreprise;
}
...
#MapsId
#OneToOne
#JoinColumn(name = "id_entreprise")
public Fournisseur getFournisseur() {
return this.fournisseur;
}
but when i try to save object :
....
fournisseur_respository.save(fournisseur);
dirigeants_repo.save( new DirigeantsEntreprise( fournisseur,...,... ));
i got this exception :
javax.persistence.EntityExistsException:
A different object with the same identifier value was already associated with
the session : [persistence.DirigeantsEntreprise#35]
PS : 35 is the ID of my fournisseur
I thinks the problem is with maps and i have two object of DirigeantsEntreprise and Fournisseur with same identifier 35.
How to resolve this problem ?
We Have to flush the session by saveAndFlush() so it will be just one object with same identifier.
....
fournisseur_respository.saveAndFlush(fournisseur);
dirigeants_repo.save( new DirigeantsEntreprise( fournisseur,...,... ));

Hibernate ObjectNotFoundException, even if records are present in table

I am working on a Spring MVC app in which there are two model classes: LocationModel and ContactModel. Below is the code:
#Entity
#Table(name="Contact")
public class ContactModel {
#Id
#Column(name="contactid")
#GeneratedValue
private int contactId;
#Column(name="contactname")
private String contactName;
#Column(name="contactemail")
private String email;
#Column(name="contactphone")
private String phone;
#ManyToOne
#JoinColumn(name="locationid")
private LocationModel locationModel;
}
#Entity
#Table(name="Location")
public class LocationModel {
#Id
#Column(name="locationid")
#GeneratedValue
private int locationId;
#Column(name="locationname")
private String locationName;
#Column(name="locationdesc")
private String locationDescription;
#Column(name="type")
private String locationType;
#Column(name="address")
private String address;
#Column(name="state")
private String state;
#Column(name="circle")
private int circle;
#Column(name="district")
private int district;
#Column(name="town")
private int town;
#Column(name="lattitude")
private String lattitude;
#Column(name="longitude")
private String longitude;
#Column(name="locationuid")
private String locationUID;
#Column(name="category")
private String category;
#Column(name="bedcount")
private int bedCount;
#OneToMany(mappedBy = "locationModel", fetch = FetchType.EAGER)
private List<ContactModel> contactList;
}
Primary key in location table is foreign key in contact table. I have 2 records in contact table, with location id 0.
I am using following code for getting contact list:
Session session = sessionFactory.getCurrentSession();
Query query = session
.createQuery("from ContactModel where contactName like :contactName");
return query.setParameter("contactName", contactName + "%").list();
But it shows exception:
Error performing load command : org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.bizmerlin.scm.model.LocationModel#0]
17:03:31,135 ERROR [stderr] (http--127.0.0.1-9090-2) org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.bizmerlin.scm.model.LocationModel#0]
17:03:31,139 ERROR [stderr] (http--127.0.0.1-9090-2) at org.hibernate.internal.SessionFactoryImpl$1$1.handleEntityNotFound(SessionFactoryImpl.java:247)
17:03:31,141 ERROR [stderr] (http--127.0.0.1-9090-2) at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:214)
17:03:31,143 ERROR [stderr] (http--127.0.0.1-9090-2) at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:264)
Perhaps it is due to that fact that location table has no record with location id 0. If so, how can I get contact list, even if their location is null?
Use optional attribute
#ManyToOne(optional=true)
#JoinColumn(name="locationid")
private LocationModel locationModel;
http://learningviacode.blogspot.in/2011/12/one-to-many-assocition-that-is-optional.html

How to write update query in Hibernate for where clause i am using foreign key column?

when i write update query in hibernate. i am getting this error. I am using Hibernate 3.2 with MySQL 5.0.Here in UserDetails.java, Login is forign key referencing to primary key (loginId) of Login.java .
java.lang.NullPointerException
at org.hibernate.hql.ast.util.SessionFactoryHelper.findSQLFunction(SessionFactoryHelper.java:342)
at org.hibernate.hql.ast.tree.IdentNode.getDataType(IdentNode.java:266)
at org.hibernate.hql.ast.tree.BinaryLogicOperatorNode.extractDataType(BinaryLogicOperatorNode.java:168)
at org.hibernate.hql.ast.tree.BinaryLogicOperatorNode.initialize(BinaryLogicOperatorNode.java:34)
at org.hibernate.hql.ast.HqlSqlWalker.prepareLogicOperator(HqlSqlWalker.java:1007)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.comparisonExpr(HqlSqlBaseWalker.java:3992)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.logicalExpr(HqlSqlBaseWalker.java:1762)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.whereClause(HqlSqlBaseWalker.java:776)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.updateStatement(HqlSqlBaseWalker.java:358)
at org.hibernate.hql.antlr.HqlSqlBaseWalker.statement(HqlSqlBaseWalker.java:237)
at org.hibernate.hql.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:228)
at org.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:160)
at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:111)
at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:77)
at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:56)
at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:72)
at org.hibernate.impl.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:133)
at org.hibernate.impl.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:112)
at org.hibernate.impl.SessionImpl.createQuery(SessionImpl.java:1623)
Here is Service class
Date birthDay = formatter1.parse(brthDay);
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
Login login = (Login) session.get(Login.class, loginId);
Query query2 = session.createQuery("update UserDetails set name=:Name, secEmailId=:SecEmailId, dob=:DOB, gender=:Gender where Login=:LoginId");
query2.setString("Name", name);
query2.setString("SecEmailId", secEmailId);
query2.setDate("DOB", birthDay);
query2.setString("Gender", gender);
query2.setParameter("LoginId", login);
profileUpdated = query2.executeUpdate();
Here is UserDetails.java pojo class
private Long udid;
private Login login;
private String name;
private String secEmailId;
private Date dob;
private String gender;
private long createrId;
private Date createdDate;
private long updaterId;
private Date updatedDate;
settes & getters
You only have Login object in your Entity. Calling a foreign key must be an (Integer or int) to put in HQL. And you cannot call a foreign key as login.getId() because hibernate doesn't allow to use brackets in HQL. The purpose of using Integer is so that it can be set to null.
private Login login;
You have to reference to your Entity but don't want to load it from the database and just to get the foreign key, use this approach. But you need to add "insertable"=false and "updatable"=false in #Column attribute to prevent losing the correct reference to an entity. Perhaps, this is your UserDetails class.
#Entity
public class UserDetails {
//Other attributes, id, phNo, address, etc..
#Column(name = "full_name")
private String name;
#OneToMany(cascade = CascadeType.ALL) //Relationship is up to you.
#JoinColumn(name = "login_id")
private Login login; //This is object.
#Column(name = "login_id", insertable = false, updatable = false)
private Integer fkLoginId; //Here is your foreign key.
//getter and setters.
}
This won't generate another column in database because it cannot be inserted or updated and it just referenced to a column. After that, you got fkLoginId as a foreign key and update your UserDetails using HQL like this.
String name = "Updated Name";
int id = 1;
session = HibernateUtil.getSession(); //Consider declared
transaction = session.beginTransaction();
Login login = (Login) session.get(Login.class, loginId);
String hql = "update UserDetails set name=:Name where fkLoginId=:Id"; //<---Ans
Query query = session.createQuery(hql);
query.setParameter("Name", name);
query.setParameter("Id", id);
int result = query.executeUpdate();
transaction.commit();
session.close();
Hope it helps.