Results 1 to 5 of 5

Thread: How to realize a many-to-many relation type with attributes?

  1. #1
    Join Date
    May 2012
    Posts
    2

    Default 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. #2
    Join Date
    Aug 2010
    Location
    Goteborg, Sweden
    Posts
    434

    Default

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

  3. #3
    Join Date
    Aug 2011
    Location
    Seville (Spain)
    Posts
    22

    Default

    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.

  4. #4
    Join Date
    Aug 2010
    Location
    Goteborg, Sweden
    Posts
    434

    Default

    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.

  5. #5
    Join Date
    May 2012
    Posts
    2

    Default

    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>();

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •