Hibernate method giving error while insert into database - java

I am getting below error while working on the Hibernate code to insert record in the database. Please suggest what wrong I am doing here.
Hibernate: insert into feedback (fb_rating_id, fb_suggestion, fb_topic_id, user_info) values (?, ?, ?, ?)
Exception deleting record :org.hibernate.exception.GenericJDBCException: could not insert: [com.tdp.model.Feedback]
public int insertFeedback(String ratingId, String msg) {
int status = 0;
Session sess = sessionFactory.openSession();
Transaction tx = null;
try {
tx = sess.beginTransaction();
//Criteria crit = sess.createCriteria(Feedback.class);
// crit.add(Restrictions.eq("feedbackId",feedback.getFeedbackId()));
Feedback fbObj = new Feedback();
fbObj.setFbRatingId(Integer.parseInt(ratingId));
fbObj.setFbSuggestion(msg);
fbObj.setFbTopicId(null);
fbObj.setUserInfo("");
sess.save(fbObj);
tx.commit();
status = 1;
} catch (HibernateException e) {
System.out.println("Exception deleting record :" + e);
if (tx != null) {
tx.rollback();
}
} finally {
sess.close();
}
return status;
}
Feedback.java
#Table(name=TDPConstants.FEEDBACK )
public class Feedback {
private Integer feedbackId; //primary key
private Integer fbRatingId;
private Integer fbTopicId;
private String fbSuggestion ;
private String userInfo ;
#Id
#Column(name = "feedback_id",unique = true, nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
public Integer getFeedbackId() {
return feedbackId;
}
public void setFeedbackId(Integer feedbackId) {
this.feedbackId = feedbackId;
}
//all other setters & getters

Could it be because you have the conditions commented out and so it is returning more than 1 object? Hibernate throws an exception if you told it to expect 1 result but it has multiple results or no result.
Based on your comment
You have to create a new instance of Feedback and set the data on it and then pass that instance to Hibernate to insert into the database.

Related

How to show information about an entity?

I have a problem. After clicking on the "create order" button, the user is redirected to the URL: "localhost:8080/currentorder/{id}" After visiting this URL, the user should see order.text.
Attempts to solve: In the DAO, I create a method that, by the ID passed from the controller, looks for an order in HQL:
public List show(Long id) {
Transaction tx = null;
try (Session session = BogPomogi.getSessionFactory().openSession()) {
session.beginTransaction();
Query query = session.createQuery("from Order where id = :id");
query.setParameter("id", id);
List result = query.getResultList();
session.getTransaction().commit();
return result;
}
}
But as you understand, after that, the timelif could not display anything (I mean order.getStatus()) Now I still think that I need to search the database and return an object, but how? help me please
My code:
Controller
#PostMapping("/")
public String createOrder (#ModelAttribute("order") Orderdao orderdao, String text, Model model, RedirectAttributes redirectAttributes){
orderdao.createOrder(text);
redirectAttributes.addAttribute("id", orderdao.checkLastOrder());
return "redirect:/currentorders/{id}";
}
#GetMapping("/currentorders/{id}")
public String showOrder (#PathVariable("id") Long id, Orderdao orderdao, Model model, Order order){
model.addAttribute("currentOrder", orderdao.show(id));
return "order";
}
Entity
#Entity
#Table(name = "orders")
public class Order implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String text;
private String customer;
private int status;
public Order(String text, String customer, int status) {
this.text = text;
this.customer = customer;
this.status = status;
}
public Order(String customer) {
this.customer = customer;
}
public Order(){
}
//Getters and setters
Method:
public Order show(Long id) {
Transaction tx = null;
try (Session session = BogPomogi.getSessionFactory().openSession()) {
session.beginTransaction();
Query query = session.createQuery("from Order where id = :id");
query.setParameter("id", id);
List result = (List) query.getSingleResult();
session.getTransaction().commit();
return (Order) session.save(result);
}
}
I am missing your code for orderDao.create, but usually you would have a service class (annotated with Springs #Service annotation), which is injected to the controller and which is called to create the entity. You can make this service method return the ID of the just created entity. It could hence be something like public Long createOrder(OrderDao orderDao). Inside there, after calling repository.save(entity), the entity will already have the ID set (try to verify yourself with debugger: Set a breakpoint to the line before you save the entity and check the ID is null, then go one step forward and see that after save, the ID is set).
My answer:
public Order show(Long id) {
Transaction tx = null;
try (Session session = BogPomogi.getSessionFactory().openSession()) {
session.beginTransaction();
Query query = session.createQuery("select text from Order where id = :id");
query.setParameter("id", id);
String result = (String) query.getSingleResult();
session.getTransaction().commit();
session.close();
return new Order(result, "adsfreger", 1);
}
}

Associated list of entity. Getting List with null, not with right entity

I think, that is trival, but i can't recognize my logic error.
So i have:
#Entity
#Table(name = "PROJECT"))
#SequenceGenerator(name = "project_seq_generator", allocationSize = 20,
initialValue = 1, sequenceName = "project_seq")
public class Project implements Serializable, Cloneable {
/** The cost centres. */
#OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
#JoinColumn(name = "projectid")
private List<Center> costCentres = new ArrayList<Center>();
...
}
There are other variables but isn't valuable for this question
The other side - Center, doesn't have mapped this.
When i try to get the costCentres with getter then i getting a list with null values.
Is there anything bad in this mapping?
I can normally add a project, and there is a center in database with associate projectid normally.
Another question is - can i create criteria to get these associated Center's?
How i fetch it:
public ProjectDTO getProjectByID(int projectID) {
Project project = null;
try {
project = (Project) session.get(project.class, projectID);
} catch(HibernateException e) {
// blabla
}
return convertToProjectDTO(project);
}
And root:
public ProjectDTO getProjectByID(int projectID) throws HibernateException {
Transaction tx = null;
Session session = HibernateUtils.getNewSession();
ProjectDTO result = null;
ProjectManager manager = new ProjectManager(session);
try {
tx = session.beginTransaction();
result = manager.getProjectByID(projectID);
tx.commit();
} catch(Exception e) {
// Bla BLa
} finally {
HibernateUtils.conditionalRollback(session);
}
return result;
}
That was a convertTo problem, not hibernate.
Question is not valid anymore
That was problem with
return null;
In code of method convertTo
Sorry for my dumb
You get List with nulls because you initialize it in the field declaration without final word.
You have 3 options
If you need ArrayList initialization do it in the getter:
public List<Center> getCostCentres() {
if (costCentres==null)return new ArrayList<Center>();
return costCentres;
}
Or you can add final word as
private final List<Center> costCentres = new ArrayList<Center>();
Or init it in the constructor.

Hibernate: getting data from two linked tables using Ctriteria API

How can I get data from two linked tables (one-to-many: one User and many Results) by value 'ispassed' (boolean) using Ctriteria API?
private List<?> winners;
try {
SessionFactory factory = HibernateUtil.getSessionFactory();
Session hSession = factory.openSession();
Transaction tx = null;
try {
tx = hSession.beginTransaction();
winners = hSession.createSQLQuery("select * from usertable u, resulttable r where u.id = r.id where r.ispassed = true").list();
tx.commit();
} catch (Exception e) {
if (tx != null)
tx.rollback();
} finally {
hSession.close();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(winners.size()); // an exception
You can use HQL:
from usertable u, resulttable r where u.id = r.id
where r.ispassed = 1
This will return a list of [User,result] arrays.
Change you code like:
private List<?> winners;
try {
SessionFactory factory = HibernateUtil.getSessionFactory();
Session hSession = factory.openSession();
Transaction tx = null;
try {
tx = hSession.beginTransaction();
winners = hSession.createSQLQuery("from usertable u, resulttable r where u.id = r.id and r.ispassed = true").list();
tx.commit();
} catch (Exception e) {
if (tx != null)
tx.rollback();
} finally {
hSession.close();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(winners.size());
EDIT:
CriteriaBuilder b = em.getCriteriaBuilder();
CriteriaQuery<Tuple> c = b.createTupleQuery();
Root<EntityX> entityXRoot= c.from(EntityX.class);
Root<EntityY> entityYRoot = c.from(EntityY.class);
List<Predicate> predicates = new ArrayList<>();
//Here you need to add the predicates you need
List<Predicate> andPredicates = new ArrayList<>();
andPredicates.add(b.equal(entityXRoot.get("id"), entityYRoot.get("id")));
andPredicates.add(b.and(predicates.toArray(new Predicate[0])));
c.multiselect(entityXRoot, entityYRoot);
c.where(andPredicates.toArray(new Predicate[0]));
TypedQuery<Tuple> q = em.createQuery(criteria);
List<Tuple> result = q.getResultList();
You can create your entity class like below
#Entity
#Table(name="RESULTS")
public class Results implements Serializable {
#Id
#GeneratedValue()
#Column(name="ID")
private Long id;
#ManyToOne
#JoinColumn(name="USER_ID")
private User userId;
#Column(name = "IS_PASSED")
private Boolean ispassed;
other property
... getter() setter()
}
#Entity
#Table(name="USER")
public class User implements Serializable {
#Id
#GeneratedValue()
#Column(name="ID")
private Long id;
#OneToMany(mappedBy = "userId",cascade=CascadeType.ALL)
private Set<Results> resultsSet;
other property
... getter() setter()
}
And in your hibernate.cfg.xml file if set below property
<property name="hibernate.query.substitutions">true 1, false 0</property>
Execute below HQL query
String sql = "from User as user "
+ "inner join user.resultsSet"
+ "where resultsSet.ispassed= true";
Query query = getCurrentSession().createQuery(sql);
List<User> UserList = query.list();
above is how you can get List of User, now you need to Iterate User list and use getter method get all results.

Check duplicate key before commit?

I'm looking for a solution to check a duplicate key before commit my BeanFieldGroup with JPAContainer. There's some a solution for this without using CriteriaQuery ?
For example, when I execute the commit there's some way to check if the key already exists in database and returns a exception ?
I'm trying this
#Entity
#Table(name="curriculum")
public class Curriculum implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long idCurriculum;
#Email
#NotEmpty
#NotNull
#Size(max=250)
#Column(unique=true)
private String email;
}
/** BeanFieldGroup */
private final BeanFieldGroup<Curriculum> binder = new BeanFieldGroup<Curriculum>(Curriculum.class);
private final Curriculum bean = new Curriculum();
/** datasources */
private final CustomJPAContainer<Curriculum> datasource = new CustomJPAContainer<Curriculum>(Curriculum.class);
private VerticalLayout buildLayout(){
vLayout = new VerticalLayout();
vLayout.setMargin(true);
vLayout.setSpacing(true);
binder.setItemDataSource(bean);
Field<?> field = null;
//email unique key on database
field = binder.buildAndBind("Email", "email", TextLower.class);
email = (TextLower)binder.getField("email");
email.setWidth("350px");
email.setMaxLength(250);
vLayout.addComponent(email);
return vLayout;
}
#Override
public void buttonClick(ClickEvent event) {
if((event.getButton()) == btnSalvar){
try {
binder.commit();
} catch (CommitException e) {
Notification.show(e.getMessage(),
Type.ERROR_MESSAGE);
}
try {
datasource.addEntity(binder.getItemDataSource().getBean());
} catch(Exception e) {
Notification.show(e.getMessage(),
Type.ERROR_MESSAGE);
return;
}
}
After make commit I do: datasource.addEntity(binder.getItemDataSource().getBean()); if datasource.addEntity() doesn't work and does execute a generic Exception.
How do I check if email field already exist in database before commit without using CriteriaQuery, there are a way ?
Any idea ?
How about this (per Svetlin Zarev's suggestion):
binder.addCommitHandler(new CommitHandler()
{
#Override
public void preCommit(CommitEvent commitEvent) throws CommitException
{
String email = (String) commitEvent.getFieldBinder().getField("email").getValue();
EntityManager em = /* retrieve your EntityManager */;
List<?> results = em.createQuery("select idCurriculum from Curriculum where email = ?")
.setParameter(1, email)
.getResultList();
if (results.size() > 0)
throw new CommitException("Email already exists");
}
#Override
public void postCommit(CommitEvent commitEvent) throws CommitException { }
});
Change your DB to have unique indexes. It will throw an exception when you try to insert duplicate data.

OUT OF MEMORY in hibernate

Hi I have created many to one relationship in hibernate.
Following is the code for that.
there are thousands of records present in B table which is link to single record of table A. When i used getBList() method it will returns thousands of record and JAVA goes OUT OF MEMORY.
So how can i solve this problem.
#Entity
#Table(name = "A")
public class A {
private int Id;
private String aName;
private List<MksReleaseInfo> bList;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
public int getId() {
return releaseId;
}
public void setId(final int Id) {
this.Id = Id;
}
#Column(name = "aname", unique = true)
public String getAName() {
return aName;
}
public void setAName(final String aName) {
this.aName = aName;
}
#OneToMany(mappedBy = "aName")
public List<MksReleaseInfo> getBList() {
return bList;
}
public void setBList(final List<B> bList) {
this.bList = bList;
}
}
#Entity
#Table(name = "B")
public class B {
private int bIndex;
private int bpriority;
private A aName;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
protected int getBIndex() {
return mksReleaseInfoIndex;
}
protected void setBIndex(final int bIndex) {
this.bIndex = bIndex;
}
#Column(name = "priority")
public int getBPriority() {
return bpriority;
}
public void setBPriority(final int bpriority) {
this.bpriority = bpriority;
}
#ManyToOne
#JoinColumn(name = "Id")
public A getAName() {
return aName;
}
public void setAName(final A aName) {
this.aName = aName;
}
}
after all the comments i have implemented the following code. but again it gives OUT OF MEMORY. Should i have to flush the memory explicitly and how?
public List<B> getList(String name, int offset, int limit) throws DAOException {
try {
String hql = "from B where name = :name";
begin();
Query query = getSession().createQuery(hql);
query.setString("name", name);
if(offset > 0){
query.setFirstResult(offset);
}
if(limit > 0){
query.setMaxResults(limit);
query.setFetchSize(limit);
}
commit();
return query.list();
} catch (HibernateException e) {
rollback();
}
}
public Long countB(String name) throws DAOException {
try {
String hql = "select count(*) from B where name = :name";
begin();
Query query = getSession().createQuery(hql);
query.setString("name", name);
commit();
return (Long)query.uniqueResult();
} catch (HibernateException e) {
rollback();
}
}
long count = countB(name);
int counter = (int) (count / 200);
if(count%200 > 0){
counter++;
}
for(int j = 0;j<counter;j++){
lists = getList(name, j*200, 200);
for(B count1 : lists){
System.out.println(count1);
}
}
You could introduce a DAO in order to retrieve the records from B given a A object in a paged way.
For example:
public interface BDao {
Page findByA(A a, PageRequest pageRequest);
}
Maybe you could take an idea from approach taked in Spring Data
Set MaxResults property of datasource, it will set limit on number of records you are getting.
Also, you can increase java heap memory size using -Xmx256m. This will set maximum heap allocation size to 256MB. You can set it as you need.
You can use query with paging for this purpose. In Query class you can find setFirstResult and setMaxResults methods which can help you to iterate over records. If you need to load all B objects and store them you can adjust memory settings of java by setting -Xmx option. Also you can try to declare some kind of reduced class B (for example ReducedB), which contains only required fields, and use iterating with converting B to ReducedB to reduce memory usage.
Also you can check this question. I think that it is close enought to what you want.
P.S. Final solution would depend on particular issue that you want to solve.
I had the same issue. I looked at my code and server space but nothing helped. Later I looked into data and realized wrongly placed data was making application use lot of processing power. Make sure you do not have duplicated data in child class.

Categories