black sensei
black sensei

Reputation: 6677

How to create 3 or 4 way many-to-many association mapped as Entity class in JPA 2

am working with spring 3.1, hibernate 4.0.1.FINAL, and spring-data-jpa 1.0.2.RELEASE. So let's say i have a many-to-many between class A and class B that i mapped as ABMap. I also have another many-to-many between class C and class D mapped as CDMap. i have a class ABMapID annotated @Embeddable

@Embeddable
public class ABMapID{
   private String aID;
   private String bID;
}
//... setters and getters

so the mapping itself is below

 @Entity
 public class ABMap {

 @Id
@AttributeOverrides({
  @AttributeOverride(name = "aID", column = @Column(name = "a_id",insertable = false, updatable = false)),
  @AttributeOverride(name = "bID", column = @Column(name = "b_id", insertable = false,updatable = false))
})
private ABMapID ID;
@ManyToOne(targetEntity = A.class)
@JoinColumn(name = "a_id",insertable = false,updatable = false)
private A a;

@ManyToOne(targetEntity = B.class)
@JoinColumn(name = "b_id", insertable = false, updatable = false)
private B b;
//.... setters and getters  
}

Now let's say we want to change the ABMap to ACDMap where the ACDMapID is made up with aID, and CDMapID(which itself is made up with cID,dID). so my new association id is ACDMapID

 @Embeddable
 public class ACDMapID {
  private String aID;
  private CDMapID cdmapID;

} 

and the entity is mapped like so

@Entity
public class ACDMap {
   @Id
@AttributeOverrides({
  @AttributeOverride(name = "aID", column = @Column(name = "a_id",insertable = false, updatable = false)),
  @AttributeOverride(name = "cdmapID", column = @Column(name = "dcmap_id", insertable = false,updatable = false))
})
  private ACDMapID ID;

}

So running this give me this error

Caused by: org.hibernate.AnnotationException: A Foreign key refering CDMap from ACDMap has the wrong number of column. should be 2

is there a way to do that mapping ? preferable i would like to keep CDMap as such.

Upvotes: 0

Views: 926

Answers (2)

siebz0r
siebz0r

Reputation: 20329

I thought I'd give it a shot, here is the result (haven't tried it so it's pure theoretical).

@Entity
public class A
{
    @Id
    private Long id;

    @ManyToMany
    @JoinTable(name = "A_B", joinColumns={
        @JoinColumn(name = "a_id")
    }, inverseJoinColumns = {
        @JoinColumn(name = "b_id")
    })
    private Collection<B> collectionOfB;

    @ManyToMany
    @JoinTable(name = "A_C_D", joinColumns={
        @JoinColumn(name ="a_id")
    }, inverseJoinColumns = {
        @JoinColumn(name = "c_id"),
        @JoinColumn(name = "d_id")
    })
    private Collection<ACD> collectionOfCD;
}

@Entity
public class B
{
    @Id
    private Long id;

    @ManyToMany(mappedBy = "collectionOfB")
    private Collection<A> collectionOfA;
}

@Entity
public class C
{
    @Id
    private Long id;

    @ManyToMany
    @JoinTable(name = "C_D", joinColumns={
        @JoinColumn(name = "c_id")
    }, inverseJoinColumns = {
        @JoinColumn(name = "d_id")
    })
    private Collection<D> collectionOfD;
}

@Entity
public class D
{
    @Id
    private Long id;

    @ManyToMany(mappedBy = "collectionOfD")
    private Collection<C> collectionOfC;
}

@Entity
@Table(name = "C_D")
public class CD
{
    @EmbeddedId
    private CDPK key;

    @MapsId("cId")
    @ManyToOne
    private C c;

    @MapsId("dId")
    @ManyToOne
    private D D;
}

@Embeddable
public class CDPK
{
    @Column(name = "c_id")
    private Long cId;
    @Column(name = "d_id")
    private Long dId;
}

I'm really not sure this works since there is an Entity using the table C_D and a JoinTable using the same table.

If it works the database would look something like this:

| A  |       | A_B         |      | B  |
| id |------<| a_id | b_id |>-----| id |
  |
  |
  |     | A_C_D              |
  \----<| a_id | c_id | d_id |
                 \/     \/
                 |      |
                 |      |
    | C  |     | C_D         |      | D  |
    | id |----<| c_id | d_id |>-----| id |

Upvotes: 1

Sean Patrick Floyd
Sean Patrick Floyd

Reputation: 298838

You don't seem to understand the concept of JPA. You are not supposed to deal with IDs programmatically, deal with Objects instead.

You want a dynamic association based on an ids in an embeddable object. Perhaps such a construct is possible with plain Hibernate, but it certainly isn't in JPA.

The whole point of JPA is to let you deal with Objects, not database relations. As soon as you start mixing those two aspects, hell will break loose, so the JPA folks decided not to support such mixtures, and I can't blame them.

Upvotes: 0

Related Questions