Tuesday, 30 March 2010

Exception in thread "main" org.hibernate.ObjectNotFoundException: No row with the given identifier exists:

Are you working on Hibernate Many-To-One/One-To-Many with MySQL? If you're, then beware of this culprit. So how does it happens? You have two objects say 'Site' and 'Partner'. Here 'A' Partner will be dealing with multiple sites and hence the multiplicity of Many-To-One and One-To-Many mapping from both objects.

For example the Site mapping will resemble something like this;
  @Entity
  @Table(name = "site")
  public class Site
  {
    private Partner partner;
    public Site()
    {
      super();
    }

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "partnerid", nullable = true)
    public Partner getPartner()
    {
      return partner;
    }

    public void setPartner(Partner partner)
    {
      this.partner = partner;
    }
  }

While the Partner object mapping will resemble something like this;
  @Entity
  @Table(name = "partner")
  public class Partner
  {
    private List<Site> sites;
    public Partner()
    {
      super();
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "partner")
    public List<Site> getSites()
    {
      return sites;
    }

    public void setSites(List<Site> sites)
    {
      this.sites = sites;
    }
  }


From the above mappings, you'll notice that Partner has been mapped to Site using the partnerid of MySQL Table partner. A physical schema for partner and site Tables looks like this;
 Partner:
 +-----------+-------------+------+-----+
 | Field     | Type        | Null | Key |
 +-----------+-------------+------+-----+
 | id        | int(11)     | NO   | PRI |
 | name      | varchar(50) | NO   |     |
 +-----------+-------------+------+-----+

 Site:
 +-----------+-------------+------+-----+
 | Field     | Type       | Null  | Key |
 +-----------+-------------+------+-----+
 | id        | int(11)    | NO    | PRI |
 | sitename  | varchar(50)| NO    |     |
 | partnerid | int(11)    | NO    |     |
 +-----------+-------------+------+-----+
 

Because the PartnerID is integer if you have a method say getParent() in Site for example like this;
  @Transient
  public Company getParent()
  {
    if (!(getPartner() == null))
    {
      return getPartner();
    }
    return null;
  }

In MySQL , default integer is '0' , not NULL. This will cause Hibernate String to load a Partner with non-existent row with id=0 and therefore throw:
 Exception in thread "main" org.hibernate.ObjectNotFoundException: No
 row with the given identifier exists: [com.lop.testing.Partner#0]at
 org.hibernate.impl.SessionFactoryImpl$2.handleEntityNotFound(SessionFactoryImpl.java:409)at
 org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:108)at
 org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:97)at
 org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:140)at
 org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)at
 com.essensys.bluefin.Partner_$$_javassist_10.toString(Partner_$$_javassist_10.java)at 
 java.lang.String.valueOf(String.java:2826) at java.lang.StringBuilder.append(StringBuilder.java:115)

To resolve this, simply annotate the Site getPartner() method as shown below;
  @ManyToOne(fetch = FetchType.LAZY, optional = false)
  @JoinColumn(name = "partnerid", nullable = true)
  @NotFound(action = NotFoundAction.IGNORE)
  public Partner getPartner()
  {
    return partner;
  }

The existance
@NotFound(action = NotFoundAction.IGNORE)
fix the issue.
Job done! but then the question is, do you need to go through that?

4 comments:

  1. Thank you! I use xml config, but you gave me the idea.

    Great!

    By the way, could you give me some hint for this mapping:

    1. From 1 ENTITY, I want to get one EMPLOYE using ENTITY.hbm.xml and Entity.getEmploye()
    2. The relation ship:

    ENTITY.Some_code= trim (EMPLOYEE.Some_code)
    ENTITY.other_code = trim (EMPLOYEE.Emp_code)

    where Emp_code and Some_code make composite key of EMPLOYEE
    Some_code and other_code are just normal column of ENTITY.

    Thanks again

    ReplyDelete
  2. From your description above I gather you want to Map OneToMany relationship from ‘ENTITY’ as you’ve stated, to Employee hence the foreign reference Emp_code on Employee object. Do clarify if this not the case.
    Let’s assume that we have OneToMany relationship from Employer object to Employee and vice versa. The Ideal been Many employees will have One Employer, whereas an Employer can have as many employees as he/she wants. Although in some cases Employee will have many employers, I gather this is not in your case, unless clarified.
    If this is the case I assume you have an employer table and employee table also. Using hbm.xml config means you have two Java classes mapped to the tables. For example table employee has Employee.class and employer with Employer.class in your application.

    Employer.java
    public class Employer implements java.io.Serializable {
    ...
    private Set employees =
    new HashSet();
    public Set< Employee > get Employees() {
    return this. Employees;
    }
    ...
    public void set Employees(Set< Employee> Employees) {
    this. Employees= Employees;
    }
    }

    Employee.java
    public class Employee implements java.io.Serializable {

    private Employer employer;
    ...
    public Employer get Employer () {
    return this. employer;
    }

    public void set Employer (Employer employer) {
    this. employer = employer;
    }
    ...
    }

    Employer.hbm.xml


    ....









    Employee.hbm.xml





    ...



    Finally to find a specific employee you for an employer you could fetch the employer using your DaoFactory.
    Typical example
    public Employer getById(Integer id) {
    if (id == null) {
    return null;
    }
    return (Employer) getSession().get(Employer.class, id);
    }
    Public static void main(String[] arg)throws Exception
    {
    Employer employer =(Employer)getById(2);
    If(employer==null)
    throw new Exception(“Invalid Employer”);
    Set employees = employer.getEmployee();
    Iterator iter = employees.iterator();
    while (iter.hasNext()) {
    System.out.println(iter.next());
    Employee employee = (Employee)iter.next();
    //check for NPE
    If(employee !=null &&(employee.getSomeElement().Equals(“Some Value”)))
    {
    System.out.print(employee.getEmpId() +” “+employee.getName());
    }
    }
    }

    ReplyDelete
  3. I am not able to post the hbm.xml definitions. I think the tags are not rendering as you can see above.

    ReplyDelete
  4. Thank's you very much from Ukraine!
    This is very useful note

    ReplyDelete