-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: @ManyToMany relationshid is adding extra column
PostPosted: Fri Sep 14, 2012 2:37 pm 
Newbie

Joined: Fri Sep 14, 2012 1:52 pm
Posts: 3
Hi,
i have poblem with many to many relationship. I'm using jpa with hibernate (3.5.5), postrgresql 9 database and spring mvc 3.1. I have two entities: Exam (owner) and Question with many to many relationship. The application is auto creating database's tables. It creates exam table, question table and exam_question table with exam_id column, question_id column and extra column exam_question_id (with notnull option). When i trying to add a exam with questions the app throws an exception - ERROR org.hibernate.util.JDBCExceptionReporter - ERROR: empty value in column "exam_question_id" affects the reduction of the required value
Details: Failing row contains (null, 351, 3650). I dont know why hibernate creates that extra column and then is trying add null value to it...
Here is my code:
Code:
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package pl.edu.pk.exam.domain;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.codehaus.jackson.annotate.JsonAutoDetect;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.map.annotate.JsonDeserialize;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import pl.edu.pk.exam.util.JsonDateDeserializer;
import pl.edu.pk.exam.util.JsonDateSerializer;

@JsonAutoDetect
@Entity
public class Exam {

    public Exam() {}

    public Exam(Integer examId, Integer type, Integer duration, Boolean isEnd, Date startDate, Boolean negativeScore) {
        this.examId = examId;
        this.type = type;
        this.duration = duration;
        this.isEnd = isEnd;
        this.startDate = startDate;
        this.negativeScore = negativeScore;
    }
   
   
     
    @Id
    @GeneratedValue(generator = "exam_id", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name = "exam_id", sequenceName = "exam_id_seq", initialValue = 1)
    @Column(name="exam_id")
    Integer examId;

    public Integer getExamId() {
        return examId;
    }

    public void setExamId(Integer examId) {
        this.examId = examId;
    }
   
    @Basic
    @NotNull
    @Size(min = 1, max = 512)
    private String name;

    public String getName() {
        return name;
    }
   
    public void setName(String name){
        this.name = name;
    }
   
    @Basic
    Integer type;

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }
   
    @Basic
    Integer duration;

    public Integer getDuration() {
        return duration;
    }

    public void setDuration(Integer duration) {
        this.duration = duration;
    }
   
    @Basic
    @Column(name="is_end")
    private Boolean isEnd;

    public Boolean getIsEnd() {
        return isEnd;
    }

    public void setIsEnd(Boolean isEnd) {
        this.isEnd = isEnd;
    }
   
    @Basic
    @Column(name="start_date")
    @Temporal(TemporalType.TIMESTAMP)
    private Date startDate;
   
    @JsonSerialize(using=JsonDateSerializer.class)
    public Date getStartDate() {
        return startDate;
    }
   
    @JsonDeserialize(using = JsonDateDeserializer.class)
    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }
   
    @Basic
    @Column(name="negative_score")
    private Boolean negativeScore;
   
    public Boolean getNegativeScore() {
        return negativeScore;
    }

    public void setNegativeScore(Boolean negativeScore) {
        this.negativeScore = negativeScore;
    }
   
   @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(
            name="exam_question",
            joinColumns={@JoinColumn(name="exam_id")},
            inverseJoinColumns={@JoinColumn(name="question_id")}
    )
    Set<Question> questions = new HashSet<Question>();
    @JsonIgnore
    public Set<Question> getQuestions()
    {
            return questions;
    }
    @JsonIgnore
    public void setQuestions(Set<Question> questions){
        this.questions = questions;
    }
}

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

@JsonAutoDetect
@Entity
public class Question {

    public Question() {}

    public Question(Integer questionId, String question, Integer type, List<Answer> answers) {
        this.questionId = questionId;
        this.question = question;
        this.type = type;
        this.answers = answers;
    }
       
    @Id
    @GeneratedValue(generator = "question_id", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name = "question_id", sequenceName = "question_id_seq", initialValue = 1)
    @Column(name="question_id")
    Integer questionId;

    public Integer getQuestionId() {
        return questionId;
    }

    public void setQuestionId(Integer questionId) {
        this.questionId = questionId;
    }
   
    @Basic
    @NotNull
    @Size(min = 1, max = 400)
    String question;

    public String getQuestion() {
        return question;
    }

    public void setQuestion(String question) {
        this.question = question;
    }
   
    @Basic
    Integer type;

    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }
   
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "question", targetEntity = Answer.class, fetch = FetchType.LAZY)
    List<Answer> answers = new ArrayList<Answer>();
   
    List<Answer> getAnswers()
    {
            return answers;
    }
   
    public void setAnswers(List<Answer> answers){
        this.answers = answers;
    }
   
    @ManyToOne(targetEntity = Subject.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "subject_id", nullable = true)
    Subject subject;
   
//    @JsonIgnore
    public Subject getSubject()
    {
            return subject;
    }
   
//    @JsonIgnore
    public void setSubject(Subject subject)
    {
            this.subject = subject;
    }
   
    @ManyToMany(mappedBy="questions")
    private Set<Exam> exams = new HashSet<Exam>();
   
    @JsonIgnore
    public Set<Exam> getExams() {
        return exams;
    }
}


persistence.xml file
Code:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="examPU" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>exam</jta-data-source>
    ....
    <class>pl.edu.pk.exam.domain.Exam</class>
    <class>pl.edu.pk.exam.domain.Question</class>
    .....
    <properties>
      <property name="hibernate.hbm2ddl.auto" value="validate"/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
    </properties>
  </persistence-unit>
</persistence>


exam_question table
Image


Any solution?


Last edited by ezriel on Sat Sep 15, 2012 5:54 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: @ManyToMany relationshid is adding extra column
PostPosted: Fri Sep 14, 2012 11:48 pm 
Beginner
Beginner

Joined: Fri Sep 14, 2012 10:41 am
Posts: 20
I can give you an avenue to investigate. It seems to me like you are declaring an extra key for your many-to-many association. It's not wrong necessarily. Look at the use of <idbag> in the documentation or books. <idbag> does exactly what you are experiencing. It ads an extra key to your table.

So you are probably, declaring your many-to-many association so it acts like <idbag>

You are not showing the declaration of your many-to-many association in both classes. That would give a better idea of where your mistake is. Please, add the declaration of the many-to-many containers (like set or something like it) in both classes.

I hope that helps.


Top
 Profile  
 
 Post subject: Re: @ManyToMany relationshid is adding extra column
PostPosted: Sat Sep 15, 2012 5:46 am 
Newbie

Joined: Fri Sep 14, 2012 1:52 pm
Posts: 3
cp10000 wrote:
I can give you an avenue to investigate. It seems to me like you are declaring an extra key for your many-to-many association. It's not wrong necessarily. Look at the use of <idbag> in the documentation or books. <idbag> does exactly what you are experiencing. It ads an extra key to your table.

So you are probably, declaring your many-to-many association so it acts like <idbag>

You are not showing the declaration of your many-to-many association in both classes. That would give a better idea of where your mistake is. Please, add the declaration of the many-to-many containers (like set or something like it) in both classes.

I hope that helps.


I showed declaration of many-to may association.
Here is it again:
Code:
@Entity
public class Exam{  //Owner
     @Id
    @GeneratedValue(generator = "exam_id", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name = "exam_id", sequenceName = "exam_id_seq", initialValue = 1)
    @Column(name="exam_id")
    Integer examId;

    public Integer getExamId() {
        return examId;
    }

    public void setExamId(Integer examId) {
        this.examId = examId;
    }
   
....
    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(
            name="exam_question",
            joinColumns={@JoinColumn(name="exam_id")},
            inverseJoinColumns={@JoinColumn(name="question_id")}
    )
    Set<Question> questions = new HashSet<Question>();
    @JsonIgnore
    public Set<Question> getQuestions()
    {
            return questions;
    }
    @JsonIgnore
    public void setQuestions(Set<Question> questions){
        this.questions = questions;
    }
.....
}

@Entity
public class Question{
    @Id
    @GeneratedValue(generator = "question_id", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name = "question_id", sequenceName = "question_id_seq", initialValue = 1)
    @Column(name="question_id")
    Integer questionId;

    public Integer getQuestionId() {
        return questionId;
    }

    public void setQuestionId(Integer questionId) {
        this.questionId = questionId;
    }
...
    @ManyToMany(mappedBy="questions")
    private Set<Exam> exams = new HashSet<Exam>();
   
    @JsonIgnore
    public Set<Exam> getExams() {
        return exams;
    }
    @JsonIgnore
    public void setExams(Set<Exam> exams){
        this.exams = exams;
    }
...
}


How can i delete that <idbag>

[EDIT]
I found that hibernate has generated a sequence named 'exam_question_id_seq' but it doesn't use it...


Top
 Profile  
 
 Post subject: Re: @ManyToMany relationshid is adding extra column
PostPosted: Sat Sep 15, 2012 11:18 am 
Beginner
Beginner

Joined: Fri Sep 14, 2012 10:41 am
Posts: 20
To start with, I can tell you that I much favour XML Hibernate metadata specifications than annotations. It seems so much clearer and less error prone.

Secondly, I have done the exact same thing what you are doing <many-to-many> association bi-directional. It works fine and does not generate an exta id column. I reviewed all my tables with a viewer. That leads me to think that you are doing something wrong in your annotation declaration.

I had to go back to the book for your problem. You did exactly what was written in the book. I did exactly what was written in the book. The only difference between us is that way we specified it. I used XML metadata.

Let me suggest that you use XML metadata for these two classes only. You can mix annotation with XML metatdata and see what happens. Create two XML files for the two classes and comment out all Hibernate annotations in the two classes.


Top
 Profile  
 
 Post subject: Re: @ManyToMany relationshid is adding extra column
PostPosted: Sat Sep 15, 2012 11:46 am 
Beginner
Beginner

Joined: Fri Sep 14, 2012 10:41 am
Posts: 20
I just rechecked what I just stated and it is true. My <many-to-many> association worked. The only difference with yours is that I used a list rather than a set. So you will see the two keys in the columns GAMEGROUPING_ID, VEHICLE_ID and VEHICLE_IDX (order of the list). There is no extra key generated by HIBERNATE!

I wanted to send you the printout of my table with columns but it is in graphic forms. I simply did a screen capture of Microsoft SQL Server Management Studio - Revision 2. I don't have a quick way to have it in text form. You have to trust me that all my columns are OK in my <many-to-many>. I even tested it with my debugger. It works!


Top
 Profile  
 
 Post subject: Re: @ManyToMany relationshid is adding extra column
PostPosted: Sat Sep 15, 2012 2:02 pm 
Newbie

Joined: Fri Sep 14, 2012 1:52 pm
Posts: 3
cp10000 wrote:
I just rechecked what I just stated and it is true. My <many-to-many> association worked. The only difference with yours is that I used a list rather than a set. So you will see the two keys in the columns GAMEGROUPING_ID, VEHICLE_ID and VEHICLE_IDX (order of the list). There is no extra key generated by HIBERNATE!

I wanted to send you the printout of my table with columns but it is in graphic forms. I simply did a screen capture of Microsoft SQL Server Management Studio - Revision 2. I don't have a quick way to have it in text form. You have to trust me that all my columns are OK in my <many-to-many>. I even tested it with my debugger. It works!


You're right. I has changed annotations to xml mapping and extra id column disappeared :)

Thank you very much cp10000


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.