hibernate session.persist(object) create more rows in database - java

Helo,
I have method
public void createContest(Contest c) {
session.beginTransaction();
session.persist(c);
session.getTransaction().commit();
logger.info("Contest saved successfully!");
}
I call it in one place with one object but this method save the object Contest to the database 4x. What could be the problem?
Here is Contest class:
#Entity
#Table(name = "Contest")
public class Contest implements java.io.Serializable {
#Id
#Column(name="CONTEST_ID", unique = true, nullable = false, precision = 5, scale = 0)
#GeneratedValue
private int id;
#Column(name="NAME")
private String name;
#Column(name="DATE_OF_EVENT")
private Date dateOfEvent;
#Column(name="REG_OPEN")
private Date regOpen;
#Column(name="REG_CLOSE")
private Date regClose;
#Column(name="REG_RESTRICTION")
private Boolean regRestriction;
#Column(name="CAPACITY")
private int capacity;
#OneToMany(mappedBy="upperContest")
private List<Contest> precontests;
#ManyToOne(cascade={CascadeType.ALL})
#JoinColumn(name="UPPER_CONTEST_ID")
private Contest upperContest;
#ManyToMany(cascade = {CascadeType.ALL})
#JoinTable(name="MANAGING",
joinColumns={#JoinColumn(name="CONTEST_ID")},
inverseJoinColumns={#JoinColumn(name="PERSON_ID")})
private List<Person> managers;
#OneToMany(mappedBy="contest")
private List<Team> teams;
public Contest(String name, Date dateOfEvent, Date regOpen,
Date regClose, Boolean regRestriction) {
this.name = name;
this.dateOfEvent = dateOfEvent;
this.regOpen = regOpen;
this.regClose = regClose;
this.regRestriction = regRestriction;
this.precontests = new ArrayList<Contest>();
this.managers = new ArrayList<Person>();
this.teams = new ArrayList<Team>();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDateOfEvent() {
return dateOfEvent;
}
public void setDateOfEvent(Date dateOfEvent) {
this.dateOfEvent = dateOfEvent;
}
public Date getRegOpen() {
return regOpen;
}
public void setRegOpen(Date regOpen) {
this.regOpen = regOpen;
}
public Date getRegClose() {
return regClose;
}
public void setRegClose(Date regClose) {
this.regClose = regClose;
}
public Boolean getRegRestriction() {
return regRestriction;
}
public void setRegRestriction(Boolean regRestriction) {
this.regRestriction = regRestriction;
}
public int getCapacity() {
return capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
public Contest getUpperContest() {
return upperContest;
}
public void setUpperContest(Contest c) {
this.upperContest = c;
}
public List<Contest> getPrecontests() {
return precontests;
}
public void addPrecontest(Contest e) {
this.precontests.add(e);
}
public void addManager(Person p){
this.managers.add(p);
}
public void addTeam(Team t){
this.teams.add(t);
}
public List<Person> getManagers(){
return managers;
}
}
And now I have to add some text because of restrictions of stackoverflow. Such Cool. Very wow.

You haven't posted the code where you instantiate Contest and populate its fields, but upperContest is probably the cause. You have CascadeType.ALL on the mapping, so you probably are persisting one contest which has a upper contest, thus actually persisting two instances because of cascade setting. Can't know for sure without that code.

Related

org.springframework.orm.jpa.JpaSystemException: Error accessing field by reflection for persistent property

I am using Spring Boot (v 2.4.0) with Hibernate 5.4.24 and, when trying to get some information from my database, I keep getting this error message:
org.springframework.orm.jpa.JpaSystemException: Error accessing field [private int es.uc3m.orders.model.Shoppingcart.usID] by reflection for persistent property [es.uc3m.orders.model.Shoppingcart#usID] : 1; nested exception is org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private int es.uc3m.orders.model.Shoppingcart.usID] by reflection for persistent property [es.uc3m.orders.model.Shoppingcart#usID] : 1
It is kind of weird for me, because it only happens when I try to access the table Shoppingcart, since I can get informatin from the rest of the tables.
I also used the exact same entities with another project but, insetad of using Spring Boot, persistence was made with EntityManagers and it worked perfectly fine.
These are my entities:
Shoppingcart
#Entity
#NamedQuery(name="Shoppingcart.findAll", query="SELECT s FROM Shoppingcart s")
public class Shoppingcart implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int scID;
private int usID;
//bi-directional many-to-many association to Product
#ManyToMany
#JoinTable(
name="sc_has_product"
, joinColumns={
#JoinColumn(name="scID")
}
, inverseJoinColumns={
#JoinColumn(name="productID")
}
)
private List<Product> products;
//bi-directional one-to-one association to User
#OneToOne(mappedBy="shoppingcart")
private User user;
public Shoppingcart() {
}
public int getScID() {
return this.scID;
}
public void setScID(int scID) {
this.scID = scID;
}
public int getusID() {
return this.usID;
}
public void setusID(int usID) {
this.usID = usID;
}
public List<Product> getProducts() {
return this.products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
public boolean isNull() {
return getProducts().isEmpty();
}
User
#Entity
#Table(name="users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String address;
#Column(name="card_n")
private Long cardN;
private String city;
private String country;
private int cvv;
private String email;
private String exp;
private String name;
private String pass;
private String surname1;
private String surname2;
private String typeOfUser;
#Column(name="zip_code")
private int zipCode;
//bi-directional many-to-one association to Order
#OneToMany(mappedBy="user")
private List<Orders> orders;
//bi-directional many-to-one association to Product
#OneToMany(mappedBy="user")
private List<Product> products;
//bi-directional one-to-one association to Shoppingcart
#OneToOne(cascade=CascadeType.REMOVE)
#JoinColumn(name="ID", referencedColumnName="usID", insertable=false, updatable=false)
private Shoppingcart shoppingcart;
public User() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getAddress() {
return this.address;
}
public void setAddress(String address) {
this.address = address;
}
public Long getCardN() {
return this.cardN;
}
public void setCardN(Long cardN) {
this.cardN = cardN;
}
public String getCity() {
return this.city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return this.country;
}
public void setCountry(String country) {
this.country = country;
}
public int getCvv() {
return this.cvv;
}
public void setCvv(int cvv) {
this.cvv = cvv;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public String getExp() {
return this.exp;
}
public void setExp(String exp) {
this.exp = exp;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getPass() {
return this.pass;
}
public void setPass(String pass) {
this.pass = pass;
}
public String getSurname1() {
return this.surname1;
}
public void setSurname1(String surname1) {
this.surname1 = surname1;
}
public String getSurname2() {
return this.surname2;
}
public void setSurname2(String surname2) {
this.surname2 = surname2;
}
public int getZipCode() {
return this.zipCode;
}
public void setZipCode(int zipCode) {
this.zipCode = zipCode;
}
public List<Orders> getOrders() {
return this.orders;
}
public void setOrders(List<Orders> orders) {
this.orders = orders;
}
public Orders addOrder(Orders order) {
getOrders().add(order);
order.setUser(this);
return order;
}
public Orders removeOrder(Orders order) {
getOrders().remove(order);
order.setUser(null);
return order;
}
public List<Product> getProducts() {
return this.products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
public Product addProduct(Product product) {
getProducts().add(product);
product.setUser(this);
return product;
}
public Product removeProduct(Product product) {
getProducts().remove(product);
product.setUser(null);
return product;
}
public Shoppingcart getShoppingcart() {
return this.shoppingcart;
}
public void setShoppingcart(Shoppingcart shoppingcart) {
this.shoppingcart = shoppingcart;
}
public String getTypeOfUser() {
return typeOfUser;
}
public void setTypeOfUser(String typeOfUser) {
this.typeOfUser = typeOfUser;
}
}
This is the ShoppingcartDAO class:
public interface ShoppingCartDAO extends CrudRepository<Shoppingcart, Integer> {
#Query("SELECT s FROM Shoppingcart s JOIN User u ON u.id = s.usID AND u.id LIKE :id")
Shoppingcart findByUser(#Param("id") int id);
#Query("SELECT s FROM Shoppingcart s")
List<Shoppingcart> findAllShoppingCart();
}
And, finally, this is my ShoppingcartController class:
#RestController
#CrossOrigin
#EnableAutoConfiguration
public class ShoppingCartController {
#Autowired
ShoppingCartDAO scDAO;
#RequestMapping(value = "sc", method = RequestMethod.POST, produces = "application/json")
public ResponseEntity<?> assignShoppingCart(#RequestBody(required = true) Shoppingcart sc) {
try {
scDAO.save(sc);
return new ResponseEntity<Void>(HttpStatus.CREATED);
} catch(Exception e) {
return new ResponseEntity<Void>(HttpStatus.BAD_REQUEST);
}
}
#RequestMapping(value = "sc", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<?> getEveryShoppingCart() {
try {
List<Shoppingcart> sc = scDAO.findAllShoppingCart();
return new ResponseEntity<List<Shoppingcart>>(sc, (sc != null) ? HttpStatus.OK : HttpStatus.NOT_FOUND);
} catch(Exception e) {
System.out.println(e);
return new ResponseEntity<Void>(HttpStatus.BAD_REQUEST);
}
}
}
I am really going nuts as I can´t figure out what is going on with my code, so thank you in advance if you help me.
I finally fixed it. For those of you who are wondering how, I deleted the relationships between tables that I had, ending with:
Shoppingcart:
#Entity
public class Shoppingcart implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int scID;
#Column(name = "usID")
private Integer userID;
public Shoppingcart() {
}
public int getScID() {
return this.scID;
}
public void setScID(int scID) {
this.scID = scID;
}
public Integer getUserID() {
return userID;
}
public void setUserID(Integer userID) {
this.userID = userID;
}
Product:
#Entity
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int productID;
private String category;
private String color;
private String description;
private String estadoProducto;
private String fecha;
private int orderID;
private String photo;
private double price;
private int seller;
private String sexo;
private String state = "Disponible";
private String talla;
private String title;
public Product() {
}
public int getProductID() {
return this.productID;
}
public void setProductID(int productID) {
this.productID = productID;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getColor() {
return this.color;
}
public void setColor(String color) {
this.color = color;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public String getEstadoProducto() {
return this.estadoProducto;
}
public void setEstadoProducto(String estadoProducto) {
this.estadoProducto = estadoProducto;
}
public String getFecha() {
return this.fecha;
}
public void setFecha(String fecha) {
this.fecha = fecha;
}
public String getPhoto() {
return this.photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public double getPrice() {
return this.price;
}
public void setPrice(double price) {
this.price = price;
}
public String getSexo() {
return this.sexo;
}
public void setSexo(String sexo) {
this.sexo = sexo;
}
public String getState() {
return this.state;
}
public void setState(String state) {
this.state = state;
}
public String getTalla() {
return this.talla;
}
public void setTalla(String talla) {
this.talla = talla;
}
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
this.title = title;
}
public int getOrderID() {
return orderID;
}
public void setOrderID(int orderID) {
this.orderID = orderID;
}
public int getSeller() {
return seller;
}
public void setSeller(int seller) {
this.seller = seller;
}
With this, everything worked fine, but don't ask me why, because I don't know it.
Your Getters/Setters are wrongly implemented.
Like :
Actual :
public int getusID() {
return this.usID;
}
Expected :
public int getUsID() {
return this.usID;
}
Same with setter

Get data from Junction Table with Android Room

I am currently building an android app, which displays a Route, which is constructed out of multiple waypoints. I already planned the database schema (chen-notation [possibly invalid "syntax"]):
I tried to recreate the n-m relation with android room, but I can't figure out how I can retrieve the index_of_route attribute of the junction table (route_waypoint).
I want the junction table attribute index_of_route, when I get the Data like so:
#Transaction
#Query("SELECT * FROM POIRoute")
List<RouteWithWaypoints> getRoutes();
inside the POIWaypoint class (maybe as extra attribute), or at least accessible from another class which maybe is implemented like so:
#Embedded
POIWaypoint waypoint;
int indexOfRoute;
Currently I don't get the indexOfRoute attribute from the junction table.
My already created classes:
RouteWithWaypoints:
public class RouteWithWaypoints {
#Embedded
private POIRoute poiRoute;
#Relation(parentColumn = "id",entityColumn = "id",associateBy = #Junction(value = RouteWaypoint.class, parentColumn = "routeId", entityColumn = "waypointId"))
private List<POIWaypoint> waypoints;
public POIRoute getPoiRoute() {
return poiRoute;
}
public void setPoiRoute(POIRoute poiRoute) {
this.poiRoute = poiRoute;
}
public List<POIWaypoint> getWaypoints() {
return waypoints;
}
public void setWaypoints(List<POIWaypoint> waypoints) {
this.waypoints = waypoints;
}
RouteWaypoint:
#Entity(primaryKeys = {"waypointId", "routeId"}, foreignKeys = {
#ForeignKey(entity = POIWaypoint.class, parentColumns = {"id"}, childColumns = {"waypointId"}),
#ForeignKey(entity = POIRoute.class, parentColumns = {"id"}, childColumns = {"routeId"})
})
public class RouteWaypoint {
private int waypointId;
private int routeId;
// I want this attribute inside the POIWaypoint class
#ColumnInfo(name = "index_of_route")
private int indexOfRoute;
public int getWaypointId() {
return waypointId;
}
public void setWaypointId(int waypointId) {
this.waypointId = waypointId;
}
public int getRouteId() {
return routeId;
}
public void setRouteId(int routeId) {
this.routeId = routeId;
}
}
POIRoute:
#Entity
public class POIRoute{
private String name;
private String description;
#PrimaryKey(autoGenerate = true)
private int id;
private boolean user_generated;
private int parentId;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean isUser_generated() {
return user_generated;
}
public void setUser_generated(boolean user_generated) {
this.user_generated = user_generated;
}
public int getParentId() {
return parentId;
}
public void setParentId(int parentId) {
this.parentId = parentId;
}
}
POIWaypoint (please ignore the position attribute it isn't finished):
#Entity
public class POIWaypoint {
#PrimaryKey(autoGenerate = true)
private long id;
#ColumnInfo(name = "long_description")
private String longDescription;
private String title;
#ColumnInfo(name = "short_description")
private String shortDescription;
// use converter: https://developer.android.com/training/data-storage/room/referencing-data
#Ignore
private GeoPoint position;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public GeoPoint getPosition() {
return position;
}
public void setPosition(GeoPoint position) {
this.position = position;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getShortDescription() {
return shortDescription;
}
public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}
public String getLongDescription() {
return longDescription;
}
public void setLongDescription(String longDescription) {
this.longDescription = longDescription;
}
I solved my problem by manage the relation by myself. I changed my RouteDao to an abstract class to insert my own method, which manages part of the junction table by itself:
RouteDao:
private RouteDatabase database;
public RouteDao(RouteDatabase database) {
this.database = database;
}
#Query("Select * from POIRoute")
public abstract List<POIRoute> getRoutes();
#Query("SELECT * FROM POIRoute WHERE id = :id")
public abstract POIRoute getRoute(int id);
#Insert
abstract void insertRouteWithWaypoints(RouteWithWaypoints routeWithWaypoints);
public List<RouteWithWaypoints> getRoutesWithWaypoints() {
List<POIRoute> routes = this.getRoutes();
List<RouteWithWaypoints> routesWithWaypoints = new LinkedList<>();
for (POIRoute r : routes) {
routesWithWaypoints.add(new RouteWithWaypoints(r, database.wayPointDao().getWaypointsFromRoute(r.getId())));
}
return routesWithWaypoints;
}
public RouteWithWaypoints getRouteWithWaypoints(int id) {
POIRoute route = this.getRoute(id);
RouteWithWaypoints routeWithWaypoints = null;
if (route != null) {
routeWithWaypoints = new RouteWithWaypoints(route, database.wayPointDao().getWaypointsFromRoute(route.getId()));
}
return routeWithWaypoints;
}
WayPointDao:
#Query("SELECT * FROM POIWaypoint")
POIWaypoint getWaypoints();
#Query("SELECT * FROM POIWaypoint WHERE id = :id")
POIWaypoint getWaypoint(long id);
#Query("SELECT pw.*, rw.index_of_route as 'index' FROM POIWaypoint as pw Join RouteWaypoint as rw on (rw.waypointId = pw.id) where rw.routeId = :id order by 'index' ASC")
List<POIRouteStep> getWaypointsFromRoute(int id);

Springboot Jpa updating records instead of inserting

I'm doing the below query to find records that are in a temp table and dont exist in master then insert the results to the master table
#Query(value = "select b from InboundTemp b where b.transactionId NOT IN (SELECT p2.transactionId FROM Inbound p2)")
ArrayList<InboundTemp> findMissing();
However if I pass a single result object to the JpaRepository save method (To update the master table)it does an update instead of an insert.
what would I be doing wrong?
import java.io.Serializable;
import javax.persistence.*;
import java.util.Date;
#Entity
#Table(name="inbound_postpay_temp")
#NamedQuery(name="InboundPostpayTemp.findAll", query="SELECT i FROM InboundPostpayTemp i")
public class InboundPostpayTemp implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int id;
#Column(name="bill_ref_no")
private String billRefNo;
#Column(name="business_shortcode")
private String businessShortcode;
private byte clicked;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="created_at")
private Date createdAt;
private String kpresponse;
private String KPtransaction_id;
#Column(name="mpesa_sender")
private String mpesaSender;
private String msisdn;
#Column(name="Network")
private String network;
#Column(name="org_account_balance")
private float orgAccountBalance;
private String status;
#Column(name="transaction_amount")
private float transactionAmount;
#Column(name="transaction_id")
private String transactionId;
#Column(name="transaction_time")
private String transactionTime;
#Column(name="transaction_type")
private String transactionType;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="updated_at")
private Date updatedAt;
public InboundPostpayTemp() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getBillRefNo() {
return this.billRefNo;
}
public void setBillRefNo(String billRefNo) {
this.billRefNo = billRefNo;
}
public String getBusinessShortcode() {
return this.businessShortcode;
}
public void setBusinessShortcode(String businessShortcode) {
this.businessShortcode = businessShortcode;
}
public byte getClicked() {
return this.clicked;
}
public void setClicked(byte clicked) {
this.clicked = clicked;
}
public Date getCreatedAt() {
return this.createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public String getKpresponse() {
return this.kpresponse;
}
public void setKpresponse(String kpresponse) {
this.kpresponse = kpresponse;
}
public String getKPtransaction_id() {
return this.KPtransaction_id;
}
public void setKPtransaction_id(String KPtransaction_id) {
this.KPtransaction_id = KPtransaction_id;
}
public String getMpesaSender() {
return this.mpesaSender;
}
public void setMpesaSender(String mpesaSender) {
this.mpesaSender = mpesaSender;
}
public String getMsisdn() {
return this.msisdn;
}
public void setMsisdn(String msisdn) {
this.msisdn = msisdn;
}
public String getNetwork() {
return this.network;
}
public void setNetwork(String network) {
this.network = network;
}
public float getOrgAccountBalance() {
return this.orgAccountBalance;
}
public void setOrgAccountBalance(float orgAccountBalance) {
this.orgAccountBalance = orgAccountBalance;
}
public String getStatus() {
return this.status;
}
public void setStatus(String status) {
this.status = status;
}
public float getTransactionAmount() {
return this.transactionAmount;
}
public void setTransactionAmount(float transactionAmount) {
this.transactionAmount = transactionAmount;
}
public String getTransactionId() {
return this.transactionId;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
public String getTransactionTime() {
return this.transactionTime;
}
public void setTransactionTime(String transactionTime) {
this.transactionTime = transactionTime;
}
public String getTransactionType() {
return this.transactionType;
}
public void setTransactionType(String transactionType) {
this.transactionType = transactionType;
}
public Date getUpdatedAt() {
return this.updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
}
The master class is the same
Below is the method that is persisting to dB
missing = temprepo.findMissing();
for (InboundPostpayTemp inboundPostpayTemp2 : missing) {
postpaytransaction.setBillRefNo(inboundPostpayTemp2.getBillRefNo());
postpaytransaction.setBusinessShortcode("");
// postpaytransaction.setClicked("0".t);
postpaytransaction
.setCreatedAt(new java.sql.Timestamp(inboundPostpayTemp2.getCreatedAt().getTime()));
postpaytransaction.setMpesaSender(inboundPostpayTemp2.getMpesaSender());
postpaytransaction.setMsisdn(inboundPostpayTemp2.getMsisdn());
postpaytransaction.setTransactionAmount(inboundPostpayTemp2.getTransactionAmount());
postpaytransaction.setTransactionId(inboundPostpayTemp2.getTransactionId());
postpaytransaction.setTransactionType("Paybill-Repost");
postpaytransaction.setStatus("CONFIRMED");
postpaytransaction.setTransactionTime(inboundPostpayTemp2.getTransactionTime());
//postpaytransactionx.add(postpaytransaction);
inboundpostpayrepo.save(postpaytransaction);
}
The only reason why JPA does an update instead of insert is that the Primary Key already exists in your persistence layer or your table. So kindly check or post your source code in order to review it and find what is wrong (if the issue is not in your data).
Now that you have updated the question with the source code, your bug is probably on the instantiation of the postpaytransaction object.
try to insert into your loop before everything else
postpaytransaction = new PostPayTransaction ()
I had the exactly same issue. My point was that the SpringBoot was automatically recreating the DB on startup, incorrectly creating the identity column in the table.
Look for spring.jpa.hibernate.ddl-auto.

MySQLIntegrityConstraintViolationException: column "question_id" cannot be null error

i have two entity classes named Qa.java and Answeres.java
my Qa entity consists of lists of answers.
Qa.Java
#Entity
#Table(name = "qa")
public class Qa {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
private String question;
private String type;
private String description;
private String param;
private int maxlength;
#OneToMany(mappedBy = "qa", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Answers> answersList = new ArrayList<>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
public int getMaxlength() {
return maxlength;
}
public void setMaxlength(int maxlength) {
this.maxlength = maxlength;
}
public List<Answers> getAnswersList() {
return answersList;
}
public void setAnswersList(List<Answers> answersList) {
this.answersList = answersList;
}
}
Answers.java
#Entity
#Table(name = "answers")
public class Answers {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String ans_label;
private int ans_value;
private int ans_weightage;
private int is_default;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "question_id", referencedColumnName = "id",nullable = false)
private Qa qa;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAns_label() {
return ans_label;
}
public void setAns_label(String ans_label) {
this.ans_label = ans_label;
}
public int getAns_value() {
return ans_value;
}
public void setAns_value(int ans_value) {
this.ans_value = ans_value;
}
public int getAns_weightage() {
return ans_weightage;
}
public void setAns_weightage(int ans_weightage) {
this.ans_weightage = ans_weightage;
}
public int getIs_default() {
return is_default;
}
public void setIs_default(int is_default) {
this.is_default = is_default;
}
public Qa getQa() {
return qa;
}
public void setQa(Qa qa) {
this.qa = qa;
}
}
My controller from where i am trying to insert data.
TableDataController.java
#Controller
public class TabletDataController {
#Autowired
QaRepository qaRepository;
#RequestMapping(value = "/saveApiData", method = RequestMethod.GET)
public void saveApiData(){
Qa qa = new Qa();
qa.setParam("");
qa.setType("input_spinner");
qa.setDescription("");
qa.setQuestion("व्यक्तिको पहिलो नाम ?");
ArrayList<Answers> answersArrayList = new ArrayList<>();
Answers answers = new Answers();
answers.setAns_label("नेपाली");
answers.setAns_value(1);
answers.setAns_weightage(0);
answers.setIs_default(0);
answersArrayList.add(answers);
qa.setAnswersList(answersArrayList);
qaRepository.save(qa);
}
}
my qaRepository extends JpaRepository. so whenever i call this api i get an error of com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'question_id' cannot be null
what am i doing wrong?
You have a bidirectional OneToMany relationship, so you need to manually maintain both sides of the relationship. Here you are only setting the Qa side with qa.setAnswersList(answersArrayList);
You need to set the other side of your relationship manually. add:
answers.setQa(qa);
before you save your list
code as follow
public void saveApiData(){
Qa qa = new Qa();
qa.setParam("");
qa.setType("input_spinner");
qa.setDescription("");
qa.setQuestion("व्यक्तिको पहिलो नाम ?");
ArrayList<Answers> answersArrayList = new ArrayList<>();
Answers answers = new Answers();
answers.setAns_label("नेपाली");
answers.setAns_value(1);
answers.setAns_weightage(0);
answers.setIs_default(0);
answers.setQa(qa);
answersArrayList.add(answers);
qa.setAnswersList(answersArrayList);
qaRepository.save(qa);
}
when you save.you should Cascade save.Your annotations configure the relationship of the associated tables but also to associate them when they are saved

Hibernate duplicated (each row twice) inserts to MySQL Database

I read a CSV file with university courses (11000 rows) and want to insert this using hibernate into a MySQL database. The problem is that hibernate inserts each row twice. There is a bug regarding this issue. Solution should be to flush each child after persisting.
See here: Hibernate inserts duplicates into a #OneToMany collection and https://hibernate.atlassian.net/browse/HHH-6776
Here is the code from my Spring applications controller:
#RequestMapping(value = "/readcsv")
public String readCSVFile() {
entityManager.setFlushMode(FlushModeType.COMMIT);
//Load all courses and universities and add to hashmap for fast lookup.
ArrayList<Course> allCourses = (ArrayList) entityManager.createQuery("FROM Course").getResultList();
MultiValueMap courseMap = MultiValueMap.decorate(new HashMap<String, Course>());
for (Course c : allCourses) {
courseMap.put(c.getName(), c);
}
ArrayList<University> allUniversities = (ArrayList) entityManager.createQuery("FROM University").getResultList();
HashMap<String, University> universityMap = new HashMap<String, University>();
for (University u : allUniversities) {
universityMap.put(u.getName(), u);
}
Country sweden = (Country) entityManager.createQuery("SELECT c FROM Country c WHERE c.name = 'Sweden'").getSingleResult();
ArrayList<Course> coursesToAdd = new ArrayList<Course>();
//Set fixed parameters for this specific dataset.
String filename = "/Volumes/320gb/macbookpro/Documents/AntagningsstatistikVT2015.csv";
String semester = "Spring2015";
String type = "Classroom";
int pace = 100;
University u;
try {
//Read file
File fileDir = new File(filename);
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(fileDir), "UTF-8"));
String line;
//Loop lines in file
while ((line = in.readLine()) != null) {
// use comma as separator
String[] courseLine = line.split(",");
String name = courseLine[1];
String university = courseLine[2];
//See if the course is already in the database
Collection<Course> coursesWithSameName = courseMap.getCollection(name);
boolean found = false;
if (coursesWithSameName != null) {
for (Course course: coursesWithSameName) {
if (course.getUniversity().getName().equals(university)) {
System.out.println("COURSE ALREADY IN DB : " + name + " " + university);
found = true;
}
}
}
//If not, insert it
if (found == false) {
if (!universityMap.containsKey(university)) {
u = new University();
u.setName(university);
u.setCountry(sweden);
u.setUserAdded(false);
universityMap.put(u.getName(), u);
entityManager.persist(u);
entityManager.flush();
} else {
u = universityMap.get(university);
}
Course course = new Course();
course.setName(name);
course.setUniversity(u);
course.setType(type);
course.setPace(pace);
course.setSemester(semester);
courseMap.put(course.getName(), course);
coursesToAdd.add(course);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("NUMBER OF ROWS IN coursesToAdd : " + coursesToAdd.size()); //Correctly prints 11000
for (Course course : coursesToAdd) { //inserts 22000 rows to db.
entityManager.persist(course);
entityManager.flush();
}
return "redirect:/";
}
Even though I flush after each persist double rows gets inserted. I have the #Transactional annotation on the controller class, is this the reason flush doesn't solve the problem? It however seems much slower when having flush there, which seems like it runs correctly compared to when it does a bulk insert on the end without flushing each insert.
Someone have a clue what is wrong in my code?
Thank you!
Edit:
Added University and Course entities:
Course:
import com.courseportal.project.account.Account;
import com.courseportal.project.utils.AbstractTimestampEntity;
import org.hibernate.annotations.Cascade;
import java.io.Serializable;
import java.util.List;
import javax.persistence.*;
#Entity
#Table(name="courses")
public class Course extends AbstractTimestampEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
private long id;
#Column(name = "code")
private String code;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL)
#OrderBy("date desc")
private List<CourseRank> ranks;
#OneToMany(cascade = CascadeType.ALL)
#OrderBy("date desc")
private List<Comment> comments;
#OneToMany(cascade = CascadeType.ALL)
#OrderBy("date desc")
private List<UserBook> userBooks;
#ElementCollection
private List<CourseBook> courseBooks;
#ManyToMany
#JoinTable(name="courses_enrolledStudents")
private List<Account> enrolledStudents;
#OneToMany(cascade = CascadeType.ALL)
private List<Timeslot> times;
#ManyToOne
private University university;
/*
* fall
* spring
* summer
*/
private String semester;
private String teacherName;
private String courseLink;
private String requirementsLink;
/**
* Undergraduate
* Graduate
*/
private String level;
/**
* Online (MOOC - Massive Open Online Courses)
* Classroom (Traditional)
* Mixed (Lab)
*/
private String type;
/**
* How fast the course going in percentage.
*/
private int pace;
private int numberOfAssignments;
private int numberOfProjects;
private int numberOfExams;
private double credits;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public University getUniversity() {
return university;
}
public void setUniversity(University university) {
this.university = university;
}
public String getCourseLink() {
return courseLink;
}
public void setCourseLink(String courseLink) {
this.courseLink = courseLink;
}
public String getRequirementsLink() {
return requirementsLink;
}
public void setRequirementsLink(String requirementsLink) {
this.requirementsLink = requirementsLink;
}
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
}
public List<Timeslot> getTimes() {
return times;
}
public void setTimes(List<Timeslot> times) {
this.times = times;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getPace() {
return pace;
}
public void setPace(int pace) {
this.pace = pace;
}
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<CourseRank> getRanks() {
return ranks;
}
public void setRanks(List<CourseRank> ranks) {
this.ranks = ranks;
}
public void addRank(CourseRank rank) {
this.ranks.add(rank);
}
public void removeRank(CourseRank rank) {
this.ranks.remove(rank);
}
public void addComment(Comment comment) {
comments.add(comment);
}
//User books, books that are for sale getters and setters
public void removeUserBook(UserBook book) {
this.userBooks.remove(book);
}
public void addUserBook(UserBook book) {
this.userBooks.add(book);
}
public List<UserBook> getUserBooks() {
return userBooks;
}
public void setUserBooks(List<UserBook> userBooks) {
this.userBooks = userBooks;
}
public List<CourseBook> getCourseBooks() {
return courseBooks;
}
public void setCourseBooks(List<CourseBook> courseBooks) {
this.courseBooks = courseBooks;
}
public void removeCourseBook(CourseBook book) {
this.courseBooks.remove(book);
}
public void addCourseBook(CourseBook book) {
this.courseBooks.add(book);
}
public int getNumberOfAssignments() {
return numberOfAssignments;
}
public void setNumberOfAssignments(int numberOfassignments) {
this.numberOfAssignments = numberOfassignments;
}
public int getNumberOfProjects() {
return numberOfProjects;
}
public void setNumberOfProjects(int numberOfprojects) {
this.numberOfProjects = numberOfprojects;
}
public int getNumberOfExams() {
return numberOfExams;
}
public void setNumberOfExams(int numberOfexams) {
this.numberOfExams = numberOfexams;
}
public double getCredits() {
return credits;
}
public void setCredits(double credits) {
this.credits = credits;
}
public List<Account> getEnrolledStudents() {
return enrolledStudents;
}
public void setEnrolledStudents(List<Account> enrolledStudents) {
this.enrolledStudents = enrolledStudents;
}
public void addEnrolledStudent(Account student) {
this.enrolledStudents.add(student);
}
public void removeEnrolledStudent(Account student) {
this.enrolledStudents.remove(student);
}
public String getSemester() {
return semester;
}
public void setSemester(String semester) {
this.semester = semester;
}
}
And University:
import com.courseportal.project.utils.AbstractTimestampEntity;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
#Entity
#Table(name="universities")
public class University extends AbstractTimestampEntity implements Serializable {
#Id
#GeneratedValue
private int id;
private String name;
#ManyToOne
private Country country;
private boolean userAdded;
public University() {}
public University(String university) {
name = university;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Country getCountry() {
return country;
}
public void setCountry(Country country) {
this.country = country;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isUserAdded() {
return userAdded;
}
public void setUserAdded(boolean userAdded) {
this.userAdded = userAdded;
}
}

Categories