Announcement Announcement Module
Collapse
No announcement yet.
How to realize a many-to-many relation type with attributes? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to realize a many-to-many relation type with attributes?

    In JPA you need two one-to-many relation to realize a many-to-many relation with attributes.

    If I manually create a composite id for the join table class (to ensure referential integrity) I get the error message:
    More than one field was annotated with @Id in '....domain.HumanQualification'

    Can you give me a hint what I have to do to or what I am doing wrong.

    P.S .: I also tried @EmbeddedId with no success (but I am new to JPA).

    Thanks in advance

    Below you will find the code (ER Modell: The entity types Human and Qualification are connected via a n:m relation type humanQualification):


    ---------------
    import ...

    @RooJavaBean
    @RooToString
    @RooJpaActiveRecord
    @IdClass(HumanQualificationPK.class)
    public class HumanQualification {

    private float weight;

    @Id
    public long humanId;
    @Id
    public long qualificationId;

    @ManyToOne
    @JoinColumn(name = "humanId", updatable = false, insertable = false)
    @MapsId("humanId")
    private Human human;

    @ManyToOne
    @JoinColumn(name = "qualificationId", updatable = false, insertable = false)
    @MapsId("qualificationId")
    private Qualification qualification;

    }

    --------------------------------------

    import java.io.Serializable;


    public class HumanQualificationPK implements Serializable{

    private static final long serialVersionUID = 1L;
    private long humanId;

    public void setHumanId(long humanId) {
    this.humanId = humanId;
    }

    public long getHumanId(){
    return humanId;
    }

    protected long qualificationId;

    public void setQualificationId(long qualificationId) {
    this.qualificationId = qualificationId;
    }

    public long getQualificationId(){
    return qualificationId;
    }

    public HumanQualificationPK(long humanId, long qualificationId){
    this.humanId = humanId;
    this.qualificationId = qualificationId;
    }

    public int hashCode() {
    Long h = (Long) humanId;
    Long q = (Long) qualificationId;
    return (int)(h.hashCode() + q.hashCode());
    }

    public boolean equals(Object object) {
    if (object instanceof HumanQualificationPK) {
    HumanQualificationPK otherId = (HumanQualificationPK) object;
    return (otherId.humanId == this.humanId) && (otherId.qualificationId == this.qualificationId);
    }
    return false;
    }
    }

    -------------------------------
    import java.util.HashSet;

    @RooJavaBean
    @RooToString
    @RooJpaActiveRecord
    public class Human {

    @NotNull
    @Size(min = 2)
    private String name;

    @NotNull
    @Size(min = 2)
    private String firstName;

    @NotNull
    @Size(min = 2)
    private String email;

    private String description;

    private String degree;

    private String streetAndNum;

    private String city;

    private Integer postalCode;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "human")
    private Set<HumanQualification> humanQualification = new HashSet<HumanQualification>();

    }
    ---------------------------------
    ...
    import java.util.HashSet;

    @RooJavaBean
    @RooToString
    @RooJpaActiveRecord
    public class Qualification {

    @NotNull
    @Size(min = 1)
    private String keyword;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "qualification")
    private Set<HumanQualification> humanQualification = new HashSet<HumanQualification>();

    }

  • #2
    Did you read this old post:Does Roo support n-m mappings?

    Comment


    • #3
      Why do you need a manual development without Roo Shell?
      Your design is as follows:

      m:m => 1:m + m:1

      Human (id, name, ...)
      Qualification (id, name, ...)
      HumanQualification (Human.id, Qualification.id, <attributes>)
      [Human.id, Qualification.id] is the Primary Key of the m:m relation.

      Comment


      • #4
        Well, as Roo 1.2 and later support composite keys you should be able to establish the basics with Roo. Roo doesn't support everything though so from time to time you have to implement your own or other standard solutions.

        If you search for 'composite key' in the Roo forum you will find this: reference field in composite PK class and several others that address solutions that could be suitable for what you're after here.

        Comment


        • #5
          Many thanks for the answers. Finally I got it. It seems to work.

          The primary key of the join entity should be a generated id. Therefore no HumanQualificationPK is necessary. But the join entity needs the following annotation to ensure that there are not two entries with the same composite (not primary) key (human, qualification)
          @RooJavaBean
          @RooToString
          @RooJpaActiveRecord
          @Table(uniqueConstraints=@UniqueConstraint(columnN ames={"human","qualification"}), name="myUniqueConstraint")
          public class HumanQualification {

          @ManyToOne
          private Human human;

          @ManyToOne
          private Qualification qualification;

          private Float weight;
          }

          In Human and Qualification there must be "orphanRemoval=true" to delete corresponding join entities if a Human or Qualification is deleted:

          @OneToMany(cascade = CascadeType.ALL, mappedBy = "human", orphanRemoval=true)
          private Set<HumanQualification> humanQualification = new HashSet<HumanQualification>();

          Comment

          Working...
          X