5 Replies Latest reply on Jan 17, 2010 3:23 PM by ronaldosv

    Newbie question about mapping and persisting in Hibernate,JBoss Seam

    ronaldosv

      Hello everybody. Sorry for the post so long, but I could not be shorter and sorry if this post in the wrong place, but I do not know if the problem is the mapping or is it something I'm doing wrong when I try to persist the object ... .
      I have a problem to persist an object in a relation @ OneToMany. Here is the picture.
      It is a module polls, where I am developing a piece of voting, involving 3 entities; Polls, Pollsoptions and Pollsvotes basically have to do the following when the User votes on a poll:
      In Poll entity, update the number of votes adding 1 and update the last date of voting.
      In PollsOptions entity, I have to update the number of votes received for the option that the user choose, by adding the option 1
      Finally, add a record in the entity PollsVotes.


      Well, I'm using JBoss Seam and did the reverse engineering of entities using JBoss Tools, and I'm using classes that JBoss Tolls generates the entities and sessions beans, I did not see anything wrong with the mapping of entities, but the problem I have is when I try to insert a record in the entity PollsOptios, the updates that I do in the other entities work without any problem.


      Here's how the classes are mapped ...


        
      @Entity
      @Table(name = "polls", catalog = "polls")
      public class Polls implements java.io.Serializable {
              private List<Pollsvotes> pollsvoteses = new ArrayList();
              private List<Pollsoptions> pollsoptionses = new ArrayList();
      
              @OneToMany(fetch = FetchType.LAZY, mappedBy = "polls")
              public List<Pollsvotes> getPollsvoteses() {
                      return this.pollsvoteses;
              }
      
              public void setPollsvoteses(List<Pollsvotes> pollsvoteses) {
                      this.pollsvoteses = pollsvoteses;
              }
      
              @OneToMany(fetch = FetchType.LAZY, mappedBy = "polls")
              public List<Pollsoptions> getPollsoptionses() {
                      return this.pollsoptionses;
              }
      
              public void setPollsoptionses(List<Pollsoptions> pollsoptionses) {
                      this.pollsoptionses = pollsoptionses;
              }
      
      }
      
      
      @Entity
      @Table(name = "pollsoptions", catalog = "polls")
      public class Pollsoptions implements java.io.Serializable {
      
              private PollsoptionsId id;
              private Polls polls;
              private int pollsoptTotalvotes;
              private List<Pollsvotes> pollsvoteses =  new ArrayList<Pollsvotes>(0);
      
              @EmbeddedId
              @AttributeOverrides( {
                              @AttributeOverride(name = "pollId", column = @Column(name = "poll_id", nullable = false)),
                              @AttributeOverride(name = "pollsoptId", column = @Column(name = "pollsopt_id", nullable = false)) })
              @NotNull
              public PollsoptionsId getId() {
                      return this.id;
              }
      
              public void setId(PollsoptionsId id) {
                      this.id = id;
              }
      
              @ManyToOne(fetch = FetchType.LAZY)
              @JoinColumn(name = "poll_id", nullable = false, insertable = false, updatable = false)
              @NotNull
              public Polls getPolls() {
                      return this.polls;
              }
      
              public void setPolls(Polls polls) {
                      this.polls = polls;
              }
      
              @Column(name = "pollsopt_totalvotes", nullable = false)
              public int getPollsoptTotalvotes() {
                      return this.pollsoptTotalvotes;
              }
      
              public void setPollsoptTotalvotes(int pollsoptTotalvotes) {
                      this.pollsoptTotalvotes = pollsoptTotalvotes;
              }
      
              @OneToMany(fetch = FetchType.LAZY, mappedBy = "pollsoptions")
              public List<Pollsvotes> getPollsvoteses() {
                      return this.pollsvoteses;
              }
      
              public void setPollsvoteses(List<Pollsvotes> pollsvoteses) {
                      this.pollsvoteses = pollsvoteses;
              }
      }
      
      @Entity
      @Table(name = "pollsvotes", catalog = "polls")
      public class Pollsvotes implements java.io.Serializable {
      
              private PollsvotesId id;
              private Users users;
              private Pollsoptions pollsoptions;
              private Polls polls;
              private Date pollsvoteDate;
      
              public Pollsvotes() {
              }
      
              public Pollsvotes(PollsvotesId id, Users users, Pollsoptions pollsoptions,
                              Polls polls, Date pollsvoteDate) {
                      this.id = id;
                      this.users = users;
                      this.pollsoptions = pollsoptions;
                      this.polls = polls;
                      this.pollsvoteDate = pollsvoteDate;
              }
      
              @EmbeddedId
              @AttributeOverrides( {
                              @AttributeOverride(name = "usrId", column = @Column(name = "usr_id", nullable = false)),
                              @AttributeOverride(name = "pollId", column = @Column(name = "poll_id", nullable = false)) })
              @NotNull
              public PollsvotesId getId() {
                      return this.id;
              }
      
              public void setId(PollsvotesId id) {
                      this.id = id;
              }
      
              @ManyToOne(fetch = FetchType.LAZY)
              @JoinColumn(name = "usr_id", nullable = false, insertable = false, updatable = false)
              @NotNull
              public Users getUsers() {
                      return this.users;
              }
      
              public void setUsers(Users users) {
                      this.users = users;
              }
      
              @ManyToOne(fetch = FetchType.LAZY)
              @JoinColumns( {
                              @JoinColumn(name = "poll_id", referencedColumnName = "poll_id", nullable = false, insertable = false, updatable = false),
                              @JoinColumn(name = "pollsopt_id", referencedColumnName = "pollsopt_id", nullable = false, insertable = false, updatable = false) })
              @NotNull
              public Pollsoptions getPollsoptions() {
                      return this.pollsoptions;
              }
      
              public void setPollsoptions(Pollsoptions pollsoptions) {
                      this.pollsoptions = pollsoptions;
              }
      
              @ManyToOne(fetch = FetchType.LAZY)
              @JoinColumn(name = "poll_id", nullable = false, insertable = false, updatable = false)
              @NotNull
              public Polls getPolls() {
                      return this.polls;
              }
      
              public void setPolls(Polls polls) {
                      this.polls = polls;
              }
      
              @Temporal(TemporalType.TIMESTAMP)
              @Column(name = "pollsvote_date", nullable = false, length = 23)
              @NotNull
              public Date getPollsvoteDate() {
                      return this.pollsvoteDate;
              }
      
              public void setPollsvoteDate(Date pollsvoteDate) {
                      this.pollsvoteDate = pollsvoteDate;
              }
      }
      



      Here is the method Vote I wrote to perform the vote, without control of transaction yet, only the first steps ... and really do not know if this is correct nd best way to do this, before to try this approach, I tried add the PollsVotes entity in the attribute pollsvoteses of the entity Polls and persist, but nothing happened, so I decided to try this approach and I am getting the following error:
      insert into polls.dbo.pollsvotes (pollsvotedate, pollid, usrid) values (?, ?, ?)
      17:37:24,782 WARN JDBCExceptionReporter SQL Error: 515, SQLState: 23000
      17:37:24,782 ERROR JDBCExceptionReporter Cannot insert the value NULL into column 'pollsopt
      id', table 'polls.dbo.pollsvotes'; column does not allow nulls. INSERT fails.
      17:37:24,783 ERROR AbstractFlushingEventListener Could not synchronize database state with session
      org.hibernate.exception.ConstraintViolationException: could not insert: org.domain.pollsweb.entity.Pollsvotes


      The correct SQL statment would be :
      insert into polls.dbo.pollsvotes (pollsvotedate, pollid, usrid,pollsoptid) values (?, ?, ?, ?)


      Basically he is ignoring the pv.setPollsoptions (po), which is listed in the code below.


      @Name("pollsHome")
      public class PollsHome extends EntityHome<Polls> {
      
              @In(create = true)
              CategoriesHome categoriesHome;
              @In(create = true)
              UsersHome usersHome;
      
              public void vote(int optionVotedId){
                      Iterator<Pollsoptions> it = getPollsoptionses().iterator();
                      boolean foundVotedOpt = false;
                      Pollsoptions po = null;
                      // TODO - find a best way to do this
                      while (it.hasNext() && !foundVotedOpt ){
                              po = it.next();
                              if (po.getId().getPollsoptId() == optionVotedId) {
                                      foundVotedOpt = true;
                              }
                      }
                      po.setPollsoptTotalvotes(po.getPollsoptTotalvotes()+1);
                      getInstance().setPollTotalvotes(getInstance().getPollTotalvotes()+1);
                      getInstance().setPollLastvotedate(new java.util.Date());
                      PollsvotesId id = new PollsvotesId(getInstance().getUsers().getUsrId(), 
                                                                 getInstance().getPollId());
                      Pollsvotes pv =  new PollsvotesHome().getInstance();
                      pv.setId(id);
                      pv.setPolls(getInstance());
                      pv.setPollsoptions(po);
                      pv.setPollsvoteDate(new java.util.Date());
                      pv.setUsers(getInstance().getUsers());
                      PollsvotesHome pvHome = new PollsvotesHome();
                      pvHome.setInstance(pv);
                      persist();
                      pvHome.persist();
              }
      }
      



      Someone please tell me where I am wrong??


      Grateful


      Ronaldo.

        • 1. Re: Newbie question about mapping and persisting in Hibernate,JBoss Seam
          lvdberg

          Hi,


          You shouldn't create Home objects with the a new operator. Basically Seam doesn't intercepts these classes. Try to inject the home object and set create true, or define home objects in components.xml and refresh/configure them in your code.


          generally speaking, in Seam you should try to forget new-


          Leo

          • 2. Re: Newbie question about mapping and persisting in Hibernate,JBoss Seam
            ronaldosv

            Hello Leo, thanks for the answer.
            I did what you said and thanks for the tip, I come from Java 1.3 and 1.4,
            and things have changed a lot, there are many concepts and new things that I
            to assimilate in such a short time, this is a good challenge.
            Well, unfortunately inject the object as you said, did not solve the problem and I think it's a mapping issue, but I still can not see exactly where it is. I think the problem is one of the relationships that the PollsVotes  entity has with Polls entity and the PollsOptions entity. I'm trying to find a solution but still do not see a light at the end of the tunnel.


            Thank you very much.


            Ronaldo.

            • 3. Re: Newbie question about mapping and persisting in Hibernate,JBoss Seam
              ronaldosv

              One thing I forgot to mention and that may not be clear,  the PollsVotes entity represents a relationship of many to many.

              • 4. Re: Newbie question about mapping and persisting in Hibernate,JBoss Seam
                lvdberg

                Hi,


                if your Polls and Pollvotes should be a relation of many-to-many, than your mapping is not correct.There should be such an annotation on both involved entities. I assume now that you have three tables for the many-to-many. I don't know what the status of seam-gen is at the moment, but it always gave me a lot of headaches for the many-to-many. We use it for the first go, but we always handcraft the many-to-many's


                It should be something like (adapt it to whatever you need):





                @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
                @JoinTable(name = "Entity1_Entity2",  
                     joinColumns = { @JoinColumn(name = "entity1_ID", nullable = false, updatable = false) ,           inverseJoinColumns = { @JoinColumn(name = "entity2_ID", nullable = false, updatable = false) })
                



                You can make it bi-directional by also using the mappedBy attribute. A intermediate table with additional fields is a little bit trickier, but can be done. You need to make an additional class which defines the relationship and forms the mapping to the db-table.


                Leo


                 

                • 5. Re: Newbie question about mapping and persisting in Hibernate,JBoss Seam
                  ronaldosv

                  Hello Leo, thanks again for the reply.
                  I am using Seam 2.1 and apparently it still does not correctly generate the mappings for many to many, I am using the generated classes and project structure as only first go too.
                  I'll try this approach, I am not an expert on hibernate, I have worked on some projects, but never from the beginning, when I started work mapping between the tables were ready, and there are not anotations that was Java 1.4 . There are not many examples of mapping many to many on the Internet. But just to explain a little better the picture, you supose correctly I have 3 tables, but the table that holds the relationship many to many, in this case pollsvotes, its receives a foreign key of the users table, because one of the rules of business is a registered user can not vote more than once in the same poll, also in this table is recorded the date of the vote, then the purpose of this table is to know which poll the user voted and which option he chose, for this reason the relationship that this table has with the polls and pollsoptions tables.


                  thank you very much.


                  Ronaldo.