views:

215

answers:

4

Assuming the following mappings are provided:

<class name="A" table="a_table">
  <id name="id"/>
  <many-to-one name="entityB" column="fk_B" not-null="false" unique="true"/>
</class>

<class name="B" table="b_table">
  <id name="id"/>
</class>

Java class:

public class A {
   private long id;
   private B entityB;
   // getters and setters skipped
}

Is it possible to change the Hibernate mapping so that foreign key is still enforced and created by Hibernate upon startup, but class A would look like as the following:

public class A {
   private long id;
   private long idOfB;
   // getters and setters skipped
}

I understand that if I convert <many-to-one... into a <property... this would work, but foreign key would not be enforced by the database.

I need to do this because object B might (or might not) be initialized separately which sometimes causes org.hibernate.LazyInitializationException: could not initialize proxy - no Session exceptions to occur when a.getB() is called. I would prefer to have it as a long idOfB and load whole object whenever is necessary; this would also make loading of object A quicker.

I believe my question is very similar to this one, yet the offered solution (to use lazy loading) is not appropriate in my case as even if I call a.getB().getId(), I'd get LazyInitializationException whereas if I call a.getIdOfB() I wouldn't.

Thanks very much in advance.

+3  A: 

You could always create the Foreign Key DDL manually in your hibernate hbm.xml file:

<hibernate-mapping>
    ...
    <database-object>
        <create>[CREATE FK]</create>
        <drop>[DROP FK]</drop>
    </database-object> 
</hibernate-mapping>

You can also scope this if different dialects need to be supported.

Check out 5.7. Auxiliary database objects

mtpettyp
A: 

Another approach you could take is to define the FK with your B mapping rather than the A mapping. I've added the JPA code, you'd have to translate this to your hibernate mapping file if you're not using annotations.

@Entity
public class B
{
    private long id;
    private List<A> aList;

    @Id
    @Column( name = "ID" )
    public long getId()
    {
        return id;
    }

    @OneToMany
    @JoinColumn( name = "B_ID" )
    public List<A> getAList()
    {
        return aList;
    }
    public void setId( long id )
    {
        this.id = id;
    }
    public void setAList( List<A> aList )
    {
        this.aList = aList;
    }        
}

A.java would not look like this:

@Entity
public class A
{
    private long id;
    private long idOfB;

    @Id
    @Column( name = "ID" )
    public long getId()
    {
        return id;
    }
    @Column( name = "B_ID" )
    public long getIdOfB()
    {
        return idOfB;
    }
    public void setId( long id )
    {
        this.id = id;
    }
    public void setIdOfB( long idOfB )
    {
        this.idOfB = idOfB;
    }   
}
mtpettyp
A: 

I recommend you to associate objects to objects to get full advantages of Hibernate. I think the problem is the exception you get. This is because Hibernate session is already closed when you try to get the lazy object. There are several posts in this blog which show answers to this problem, for example this one:link text.

In case you're using spring you can use OpenEntityManagerInViewFilter so the session will keep opened until the view is renderes.

Javi
Thanks for your answer, but I'm fully aware of why lazy loading exceptions are thrown and how to deal with them. However, this is a special case where I would like the framework be more flexible and do the job for me. Because that's why they are written, right? Finally, I don't think what I'm asking is too much for a O-R mapping framework, isn't it?
mindas
+2  A: 

Hi,

As said

I understand that if I convert <many-to-one... into a <property... this would work, but foreign key would not be enforced by the database.

So my advice is: use both

public class EntityA {

    private Integer idOfB;

    private EntityB entityB;

    // getter's and setter's

}

And

<class name="A" table="a_table">
    <id name="id"/>
    <property name="idOfB" column="fk_B" not-null="false" unique="true"/>
    <many-to-one name="entityB" update="false" insert="false" column="fk_B"/>
</class>

Notice when two properties share the same column, you have to put settings about it in just one property. Otherwise, Hibernate will complain some errors. It explains why i define update="false" and insert="false" in entityB property.

regards,

Arthur Ronald F D Garcia
Nice and slick! And it works...
mindas