dimitar wrote:
In this case, a third column is needed, and I am not sure if Hibernate can handle such "complex" many-to-many associations. Therefore, one should use two one-to-many associations and an additional entity, as I've described.
I do agree with your point. However I did a little test with your code and it appeared to be working for me. So, I post the files here so that you decide what is different:
Location:
Code:
package test.model.data.jpa;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "LOCATION")
public class Location {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "ID")
protected long identifier;
@OneToMany(cascade= CascadeType.ALL, mappedBy = "parentLocation")
protected Set<LocationRelation> parentRelations = new HashSet<LocationRelation>();
@OneToMany(cascade= CascadeType.ALL, mappedBy = "childLocation")
protected Set<LocationRelation> childRelations = new HashSet<LocationRelation>() ;
public void addParentRelation(LocationRelation rel) {
parentRelations.add(rel);
rel.childLocation = this;
}
public void addChildRelation(LocationRelation rel) {
childRelations.add(rel);
rel.parentLocation = this;
}
}
LocationRelation:
Code:
package test.model.data.jpa;
import javax.persistence.*;
@Entity
@Table(name = "LOCATION_RELATION")
public class LocationRelation {
@Id
@Column(name="ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected long id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "CHILD_ID", nullable = false)
protected Location childLocation;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "PARENT_ID", nullable = false)
protected Location parentLocation;
}
And the test code:
Code:
import test.model.data.jpa.Location;
import test.model.data.jpa.LocationRelation;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
/**
* @author Farzad Kohantorabi
* @created Dec 10, 2007
*/
public class Driver {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("manager1");
EntityManager em = emf.createEntityManager();
Location l1 = new Location();
Location l2 = new Location();
LocationRelation lr = new LocationRelation();
l1.addChildRelation(lr);
l2.addParentRelation(lr);
em.getTransaction().begin();
em.merge(l1);
em.flush();
em.getTransaction().commit();
em.close();
emf.close();
}
}
and persitence.xml:
Code:
<persistence 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"
version="1.0">
<persistence-unit name="manager1" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>test.model.data.jpa.Location</class>
<class>test.model.data.jpa.LocationRelation</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect"/>
<property name="hibernate.connection.driver_class" value="net.sourceforge.jtds.jdbc.Driver"/>
<property name="hibernate.connection.username" value="sa"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.url"
value=""/>
<property name="hibernate.max_fetch_depth" value="3"/>
<property name="hibernate.show_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>
One main difference I can tell you is the primary key for the relation table but I assume you did something for that anyways. Well, hibernate perfectly stored the relation in the database and inserted two locations.
Hibernate: insert into LOCATION default values
Hibernate: insert into LOCATION default values
Hibernate: insert into LOCATION_RELATION (CHILD_ID, PARENT_ID) values (?, ?)
I didn't observe any extra insert. However, I was getting unexpected result when the identity of Location class was not set to AUTO which means it somehow confused hibernate which object is which. I do believe your problem should be something close to this. Let me know how this works for you.
Farzad-