6

I'd like to apply JPA in the following (simplified) database:

NODE                         AUTHORITY
-----                        ----------
idNode int                   idAuthorities int
nameNode varchar(50)         person varchar(255)
idAuthorities int            rank int
PRIMARY KEY (idNode)         PRIMARY KEY (idAuthorities, rank)
FOREIGN KEY (idAuthorites)

So one node can have multiple authorities and one authority can be referenced by multiple nodes.

And I wanted my classes to look like:

@Entity
@Table(name="NODE")
public class Node {

    private Integer id;
    private String nameNode;
    private Set<Authority> authorities;

    // ... getter and setter normaly annoted for "id" and "nameNode"

    @ManyToMany
    public Set<Authority> getAuthorities(){
        return authorities;
    }
    // ... setter ...

}

@Entity
@Table(name="AUTHORITY")
public class Authority {

    private AuthorityPK pk;
    private String person;
    privat Set<Node> nodes;

    // ... getter and setter normaly annoted for "person"

    @Id
    public AuthorityPK getPk(){
        return this.pk
    }
    // ... setter ...

    @ManyToMany
    public Set<Node> getNodes(){
        return nodes;
    }
    // ... setter ...

}

@Embeddable
public class AuthorityPK implements Serializable {
    private Integer idAuthorities;
    private Integer rankAuthorities;

    // override of equals and hashCode
}

But the annotation "@ManyToMany" seems to be usable only with "@JoinTable", which isn't usable (as far as I understand) in that case. Does anyone know if there is a way arroud beside modifying the database?

JeromeB
  • 95
  • 1
  • 1
  • 8
  • 2
    What you describe is not a many-to-many relation, but a many-to-one relation between 'nodes' and 'authorities'. Many 'nodes' can have the same (one) 'authorities'. Never has any 'nodes' more than one 'authorities'. I have the feeling, that your class names 'Nodes' and 'Authorities' are wrongly chosen. Each instance of these classes seems to represent what one usually would refere to as one 'Node' or 'Authority'. – Philipp Matthias Schäfer Jul 29 '14 at 11:58
  • That is true, the names of the classes are pourly choosed. But one entry of the class "Nodes" can refer to multiple "Authorities" because any number of them can have the same field "idAuthority" (the primary key is the combination of the "rankAuthority" and the "idAuthority") – JeromeB Jul 29 '14 at 12:10
  • JPA does not allow this as it requires foreign keys to reference the full primary key for identity purposes. You will need to look at provider specific code outside of JPA to make it work. – Chris Jul 29 '14 at 15:03

1 Answers1

9

JPA does not allow this as it requires foreign keys to reference the full primary key for identity purposes, and it might not work well with caching. If you can, I would recommend switching to a more traditional model using a relation table that uses the actual primary keys.

If your provider allows mapping partial pks (I believe Hibernate does), what you would do is make two 1:M mappings each using a JoinColumn instead of JoinTable, but mark the one on Node->Authority as insertable=false, updatable=false

For example, something like:

public class Node {
    @Id
    private Integer id;
    private String nameNode;
    @OneToMany
    @JoinColumn(name = "idAuthorites", referencedColumnName = "idAuthorites", insertable=false, updatable=false)
    private Set<Authority> authorities;
    ...

public class Authority {
    @Id
    private AuthorityPK pk;
    private String person;
    @OneToMany
    @JoinColumn(name = "idAuthorites", referencedColumnName = "idAuthorites")
    private Set<Node> nodes;
    ...
Chris
  • 20,138
  • 2
  • 29
  • 43