11 Replies Latest reply on Feb 8, 2009 7:26 PM by Hugo Pragt

    ManyToOne wont persist. help?

    Hugo Pragt Newbie

      I'm sure this must be simple but I cannot see what I am doing wrong.
      I have a program that read in files and creates records in the database.
      Its about storing calls and telephone numbers.
      A call has 2 numbers it must relate to.
      I read in the file and create the telephone number classes
      I create a call and set the telephone numbers.
      then I call persist()


      This went wrong because 2 calls can be made to the same phone number resulting in a unique constraint voilation .
      so far I can understand.
      However, i cannot find a solution for this situation.


      First I tried finding the telephone numbers first with em.find() and persisting them when not found. The inserting them to the call and calling persist() on the call(). Calling persist() on the call results in a the same unique constraint voilation.


      The I used merge() instead of persist() on the new telephonenumbers. That results in a deadlock?!?


      I have been banging my head on this for far too long.
      I guess it must be simple but I cant see it right now. How should I do this?


      Does it matter that there are multiple thread concurrently adding calls and telephone numbers to the database?


      @Entity
      @Name("telephonenumber")
      public class TelephoneNumber implemeents serializable {
          private String all;
          private String country;
          private String number;
      
      
          @Id
          @Column(length=30)
          public String getAll() {
              return all;
          }
      
          // All other getters and setters
      }
      
      



      @Entity
      @Name("call")
      Public class Call implements Serializable {
          private long id;
          private TelephoneNumber from;
          private TelephoneNumber to;
          private Date start;
      
          @Id
          public void setId(Long callId) {
              return id;
          }
      
          @ManyToOne
          public TelephoneNumber getFrom() {
              return from;
          }
      
          @ManyToOne
          public TelephoneNumber getTo() {
              return to;
          }
          
          // All other getters and setters
      }
      


        • 1. Re: ManyToOne wont persist. help?
          Daniel Hinojosa Master

          Well, you don't have any @JoinColumn on the many to one relationships that's for sure.  But that may not be your only problem.  Serializable needs to have a capital S on your TelephoneNumber entity, and implements is misspelled on your TelephoneNumber entity too.  Can you clean up your code, try it, and post again?


          • 2. Re: ManyToOne wont persist. help?
            Hugo Pragt Newbie

            Hello, Im behind the devlopment machine now so I can cut and paste code instead of typing over.


            Telephone Number:


            package nl.unc.mmt.entity;
            
            import java.io.Serializable;
            
            import javax.persistence.Column;
            import javax.persistence.Entity;
            import javax.persistence.Id;
            import javax.persistence.NamedQueries;
            import javax.persistence.NamedQuery;
            
            import nl.unc.mmt.util.TelephoneNumberType;
            
            import org.jboss.seam.annotations.Name;
            
            /**
             * Utility class for telephone numbers.
             * @author Hugo Pragt All rights reserverd
             *
             */
            @Entity
            @Name("telephonenumber")
            @NamedQueries({
                @NamedQuery(name="telephonenumber.findByNumber", query="select nr from TelephoneNumber nr where nr.number =:number")
            })
            public class TelephoneNumber implements Serializable {
            
                private static final long serialVersionUID = -1134570748748658402L;
                private String cli;
                private String cps;
                private String countrycode;
                private String number;
                private TelephoneNumberType type = TelephoneNumberType.UNKNOWN;
                private Short category;
                
                /**
                 * whether this telephone number is a national, international etc number.
                 * defaults to UNKNOWN
                 * @return the type of the number
                 * @see TelephoneNumberType
                 */
                public TelephoneNumberType getType() {
                    return type;
                }
            
                /**
                 * @param type the type of the number
                 * @see TelephoneNumberType
                 */
                public void setType(TelephoneNumberType type) {
                    this.type = type;
                }
            
                /**
                 * @return the category of the number
                 */
                public Short getCategory() {
                    return category;
                }
            
                /**
                 * @param category the category of the number to set
                 */
                public void setCategory(Short category) {
                    this.category = category;
                }
            
                /**
                 * @return all digits of telephone number
                 */
                @Id
                @Column(length=24)
                public String getCli() {
                    return cli;
                }
            
                /**
                 * @param digits id to set
                 * @see #setCps(String)
                 * @see #setCountrycode(String)
                 * @see #setNumber(String)
                 */
                public void setCli(String digits) {
                    cli = digits;
                }
            
                /**
                 * @return the Carrier PreSelect code 
                 */
                public String getCps() {
                    return cps;
                }
            
                /**
                 * @param cps the Carrier PreSelect code to set
                 */
                public void setCps(String cps) {
                    this.cps = cps;
                }
                /**
                 * @return the country code (without prefix zero's)
                 */
                public String getCountrycode() {
                    return countrycode;
                }
            
                /**
                 * @param countrycode the country code to set
                 */
                public void setCountrycode(String countrycode) {
                    this.countrycode = countrycode;
                }
            
                /**
                 * @return the number without CPS or country code
                 */
                public String getNumber() {
                    return number;
                }
            
                /**
                 * @param number the number without CPS or country code
                 */
                public void setNumber(String number) {
                    this.number = number;
                }
                
                /**
                 * outputs correctly formatted telephone number.
                 * non-filled fields are ignored resulting in an ampty string for a
                 * non-initialised telephone number. 
                 * @return CPS + CountryCode + Number
                 */
                @Override()
                public String toString() {
                    StringBuffer result = new StringBuffer();
                    if (cps != null) {
                        result.append(cps);
                    }
                    if (countrycode != null) {
                        result.append("00");
                        result.append(countrycode);
                    }
                    if (number != null) {
                        result.append(number);
                    }
                    return result.toString();
                }
                /**
                 * @see java.lang.Object#equals(java.lang.Object)
                 */
                @Override
                public boolean equals(Object obj) {
                    if (obj == null) {
                        return false;
                    } if (! (obj instanceof TelephoneNumber)) {
                        return false;
                    }
                    TelephoneNumber other = (TelephoneNumber)obj;
                    if (cli == null) {
                        return other.cli == null;
                    }
                    return cli.equals(other.cli);
                }
            
                /**
                 * @see java.lang.Object#hashCode()
                 */
                @Override
                public int hashCode() {
                    if (cli == null) {
                        return 0;
                    }
                    return cli.hashCode();
                }
            
            }
            


            Call



            I have removed some of the 80+ fields in this class


            package nl.unc.mmt.entity;
            
            import java.io.Serializable;
            import java.util.Date;
            import java.util.HashSet;
            import java.util.Set;
            
            import javax.persistence.CascadeType;
            import javax.persistence.Column;
            import javax.persistence.Entity;
            import javax.persistence.Id;
            import javax.persistence.ManyToMany;
            import javax.persistence.ManyToOne;
            import javax.persistence.NamedNativeQueries;
            import javax.persistence.NamedNativeQuery;
            import javax.persistence.NamedQueries;
            import javax.persistence.NamedQuery;
            
            import nl.unc.mmt.util.LDCStatus;
            import nl.unc.mmt.util.ericsson.AxeCDR;
            
            import org.jboss.seam.annotations.Name;
            
            /**
             * A CDR read directly from data source by the CDR creator.
             * @author Hugo Pragt. All rights reserved
             *      
             */
            @Entity
            @Name("cdr")
            public class Cdr implements Serializable {
            
                private static final long serialVersionUID = 4003988589514561342L;
            
                    private Long id;
            
                 /**
                  * true = this is a (fake) test CDR
                  * default = false
                  */
                 private boolean test = false;
            
                 private TelephoneNumber anumber;
                 
                 private TelephoneNumber aNumber_UserPresented;
            
                 private TelephoneNumber bnumber;
            
                 private TelephoneNumber bNumber_AfterAnalyses;
            
                 private TelephoneNumber xnumber;
            
                 private Date start;
            
                 private long duration;
            
                 private boolean beingProcessed = false;
            
                 @Id
                 public Long getId() {
                      return id;
                 }
            
                 public void setId(Long cdrId) {
                      this.id = cdrId;
                 }
                 // http://java.sun.com/javaee/5/docs/api/javax/persistence/Column.html
                 @Column(columnDefinition="tinyint", length=4)
                 public boolean isTest() {
                      return test;
                 }
            
                 public void setTest(boolean isTest) {
                      this.test = isTest;
                 }
            
                 // http://java.sun.com/javaee/5/docs/api/javax/persistence/Column.html
                 @Column(columnDefinition="tinyint", length=4)
                 public boolean isRedirected() {
                      return redirected;
                 }
            
            //     @ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST})
                 @ManyToOne
                 public TelephoneNumber getAnumber() {
                      return anumber;
                 }
            
                 public void setAnumber(TelephoneNumber number) {
                      anumber = number;
                 }
            
            //    @ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST})
                 @ManyToOne
                 public TelephoneNumber getANumber_UserPresented() {
                      return aNumber_UserPresented;
                 }
            
                 public void setANumber_UserPresented(TelephoneNumber number) {
                      aNumber_UserPresented = number;
                 }
            
            //    @ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST})
                 @ManyToOne
                 public TelephoneNumber getBnumber() {
                      return bnumber;
                 }
            
                 public void setBnumber(TelephoneNumber number) {
                      bnumber = number;
                 }
            
            //    @ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST})
                 @ManyToOne
                 public TelephoneNumber getBNumber_AfterAnalyses() {
                      return bNumber_AfterAnalyses;
                 }
            
                 public void setBNumber_AfterAnalyses(TelephoneNumber number_AfterAnalyses) {
                      bNumber_AfterAnalyses = number_AfterAnalyses;
                 }
            
            //    @ManyToOne(cascade={CascadeType.MERGE,CascadeType.PERSIST})
                 @ManyToOne
                 public TelephoneNumber getXnumber() {
                      return xnumber;
                 }
            
                 public void setXnumber(TelephoneNumber number) {
                      xnumber = number;
                 }
            
                 public Date getStart() {
                      return start;
                 }
            
                 public void setStart(Date start) {
                      this.start = start;
                 }
            
                 /**
                  * 
                  * @return chargeable duration in milliseconds
                  */
                 public long getDuration() {
                      return duration;
                 }
            
                 /**
                  * 
                  * @param duration chargeable duration in milliseconds
                  */
                 public void setDuration(long duration) {
                      this.duration = duration;
                 }
            
                 @Override
                 public String toString() {
                      StringBuffer sb = new StringBuffer(Cdr.class.getSimpleName());
                      sb.append("(id=");
                      sb.append(id);
                      sb.append(",Anumber=");
                      sb.append(anumber);
                      sb.append(",Bnumber=");
                      sb.append(bnumber);
                      sb.append(",duration=");
                      sb.append(duration);
                      sb.append(')');
                      return sb.toString();
                 }
            
            
                /**
                 * @return the beingProcessed
                 */
                @Column(columnDefinition="tinyint", length=4)
                public boolean isBeingProcessed() {
                    return beingProcessed;
                }
            
                /**
                 * @param beingProcessed the beingProcessed to set
                 */
                public void setBeingProcessed(boolean beingProcessed) {
                    this.beingProcessed = beingProcessed;
                }
            
            }
            



            call writing method



                 private CorruptedCdr handleRecord(String record) {
            
                    String[] values = null;
                    if (record != null) {
                        values = record.split(",");
                    }
                    Cdr cdr = create(values);
                    cdr.setTest(true); // TODO remove setTest(true)
                    Cdr cdr2 = em.find(Cdr.class, cdr.getId());
                    if (cdr2 == null) {
                        em.persist(cdr); // changed from merge to persist to avoid double PK's
                    } else {
                        log.warn("Overwriting {0}!", cdr2);
                        em.merge(cdr);
                    }
                      log.debug("persisting new cdr {0}", cdr);
                }
                try {
                    em.flush(); // TODO remove?
                } catch(PersistenceException e) {
                    log.warn("while storing {0} in database: {1}", cdr, e);
                    throw e;
                }
                    return null;
            




            Error log


            2008-08-04 23:54:15,171 INFO  [STDOUT] Hibernate: 
                insert 
                into
                    TelephoneNumber
                    (type, number, category, cps, countrycode, cli) 
                values
                    (?, ?, ?, ?, ?, ?)
            2008-08-04 23:54:15,171 WARN  [org.hibernate.util.JDBCExceptionReporter] SQL Error: 1213, SQLState: 40001
            2008-08-04 23:54:15,187 ERROR [org.hibernate.util.JDBCExceptionReporter] Deadlock found when trying to get lock; try restarting transaction
            


            • 3. Re: ManyToOne wont persist. help?
              System Administrator Expert

              are you running load tests or accessing the EntityManager in a servlet (not thread safe)?


              you should post this on the hibernate forum.

              • 4. Re: ManyToOne wont persist. help?
                Hugo Pragt Newbie

                I'm using the entity manager from the ejb3 container (Jboss4)


                The reason I'm posting here is that the only thing I can come up with to explain the error is the transaction demarcation



                Is there anything obviously wrong with my code which I'm just overlooking?


                H


                ps. Thanks for looking!

                • 5. Re: ManyToOne wont persist. help?
                  Daniel Hinojosa Master

                  I bet your mysql log file will hold many answers for you.

                  • 6. Re: ManyToOne wont persist. help?
                    Hugo Pragt Newbie

                    solved.
                    The answer was to store the input in the database and from there handle the data.
                    End of deadlocks .

                    Hurray!

                    • 7. Re: ManyToOne wont persist. help?
                      Vasu Rao Newbie

                      Hi Hugo Pragt


                      I have also got the same problem and i am unable to solve it could you please help me in resolving the issue.


                      I mean could please explain me with more details, how did you solve it?


                      Thank you
                      Srinivas

                      • 8. Re: ManyToOne wont persist. help?
                        Hugo Pragt Newbie

                        Hi Srinivas Rao,


                        It's a bit late here now, but I will look the code up for you tomorrow.
                        Unless you are really in panic-mode?


                        Cheers,


                        Hugo

                        • 9. Re: ManyToOne wont persist. help?
                          Vasu Rao Newbie

                          Hi Hugo,


                          Thanks for your concern. As I was desperate to get  the issue resolved.
                          Without any thought, I have requested  you. I am really in panic-mode.


                          So is there any possibility of meeting you on any chat tool. otherwise ask me some queries that can bring you more clarity on my issue or suggest me how to resolve.


                          Also please let me know your convenient timing(time zone). So  that I can get in touch with you in that time.


                          Please help me.



                          Thank You,

                          Srinivas

                          • 10. Re: ManyToOne wont persist. help?
                            Hugo Pragt Newbie

                            Hi Srinivas,


                            I've had a look at the code And I'm able to call em.persist(cdr)


                            The
                            two telephone numbers have the annotations:


                            @ManyToOne(cascade={Cascasdetype.Merge,Cascadetype.PERSIST})



                            Things you could check:



                            • The annotations must be on the getters (not the setters) of the fields

                            • when you call merge instead of persists I get deadocks (merge keeps a lock maybe?)

                            • When you set a transactiontype annotation it only has effect on a business method. I found that that means a method called via the interface of an ejb.



                            I'll be available for the next few hours on msn via hotmail account : hcgragt


                            wish you succes,


                            Hugo


                            • 11. Re: ManyToOne wont persist. help?
                              Hugo Pragt Newbie

                              I created this separate method for storing telephone numbers:


                                 @TransactionAttribute(TransactionAttributeType.REQUIRED)
                                  public TelephoneNumber getPhoneNumber (String cli, TelephoneNumberType type
                                  ) throws TelephonenumberCreateException {
                                      TelephoneNumber telnr = axeutil.createTelephoneNumber(cli, type);
                                      if (telnr == null) {
                                          return null;
                                      }
                                      return em.merge(telnr);
                                  }


                              This method is called from another EJB.
                              This EJB is the factory class for CDR's:


                              cdr.setAnumber(getPhoneNumber(s[AxeCDR.CALLING_PARTY_NR], s[AxeCDR.A_SUBSCRIBER_NR_TYPE]))



                              After the CDR is created I then persist it.
                              But the telephonenumbers in the CDR are already stored and thus managed by Entity manager.



                              I probably overdone it, but at least it works.



                              If it works don't try to fix it

                              Hope it helps!