JPA entity resultset duplication with more than one collection

99 views Asked by At

The Contact entity defines relationships to two collections of entity of type email and nickname which exist in two MySQL tables.

My issue is that the result set this returns has duplicated email and nicknames.

{
  "contactId": 1,
  "givenName": "toast",
  "middleName": "brown",
  "familyName": "jam",
  "dob": "2014-11-19",
  "contactEmailAddress": [
    {
      "emailAddressId": 1,
      "emailAddress": "[email protected]",
      "contactId": 1
    },
    {
      "emailAddressId": 1,
      "emailAddress": "[email protected]",
      "contactId": 1
    },
    {
      "emailAddressId": 2,
      "emailAddress": "[email protected]",
      "contactId": 1
    },
    {
      "emailAddressId": 2,
      "emailAddress": "[email protected]",
      "contactId": 1
    }
  ],
  "contactNickname": [
    {
      "contactNicknameId": 1,
      "nickname": "mm",
      "contactId": 1
    },
    {
      "contactNicknameId": 2,
      "nickname": "mouse",
      "contactId": 1
    },
    {
      "contactNicknameId": 1,
      "nickname": "mm",
      "contactId": 1
    },
    {
      "contactNicknameId": 2,
      "nickname": "mouse",
      "contactId": 1
    }
  ]
}

If I remove the ContactNickname collection from the Contact entity the result set is as follows.

{
  "contactId": 1,
  "givenName": "toast",
  "middleName": "brown",
  "familyName": "jam",
  "dob": "2014-11-19",
  "contactEmailAddress": [
    {
      "emailAddressId": 1,
      "emailAddress": "[email protected]",
      "contactId": 1
    },
    {
      "emailAddressId": 2,
      "emailAddress": "[email protected]",
      "contactId": 1
    }
  ]
}

I expected a distinct collection of email address and a distinct collection of nicknames but this is not the case. What am I doing incorrectly.

Using JPA I have mapped the the class as follows.

@Entity
@Table(name="contact")
public class Contact implements Serializable {    
    @OneToMany(fetch=FetchType.EAGER)
    @JoinColumn(name="contact_id")
    private Collection<ContactEmailAddress> contactEmailAddress;

    @OneToMany(fetch=FetchType.EAGER)
    @JoinColumn(name="contact_id")
    private Collection<ContactNickname> contactNickname;

    public Collection<ContactEmailAddress> getContactEmailAddress(){
        return this.contactEmailAddress;
    }

    public void setContactEmailAddress(Collection<ContactEmailAddress> contactEmailAddress){        
        this.contactEmailAddress=contactEmailAddress;
    }

    public Collection<ContactNickname> getContactNickname(){
        return this.contactNickname;
    }

    public void setContactNickname(final Collection<ContactNickname> contactNickname){
        this.contactNickname=contactNickname;
    }    
}
@Entity
@Table(name="contact_email_address")
public class ContactEmailAddress implements Serializable {   
    @Id
    @GeneratedValue
    @Column(name="email_address_id")
    private int emailAddressId;

    @Column(name="email_address")
    private String emailAddress;

    @Column(name="contact_id")
    private int contactId;

  public void setContactId(int contactId){
        this.contactId=contactId;
    }

    public int getContactId(){
        return this.contactId;
    }.

   public int getEmailAddressId(){
        return emailAddressId;
    }

    public void setEmailAddressId(final int emailAddressId){
        this.emailAddressId=emailAddressId;
    }

    public String getEmailAddress(){
        return emailAddress;
    }

    public void setEmailAddress(String emailAddress){
        this.emailAddress=emailAddress;
    }
}
@Entity
@Table(name="contact_nickname")
public class ContactNickname implements Serializable {
    @Id
    @GeneratedValue
    @Column(name="contact_nickname_id")
    private int contactNicknameId;

    @Column(name="nickname")
    private String nickname;

    @Column(name="contact_id")
    private int contactId; 

    public int getContactNicknameId(){
        return contactNicknameId;
    }

    public void setContactNicknameId(final int contactNicknameId){
        this.contactNicknameId=contactNicknameId;
    }

    public String getNickname(){
        return this.nickname;
    }

    public void setNickname(String nickname){
        this.nickname=nickname;
    }    

    public void setContactId(int contactId){
        this.contactId=contactId;
    }

    public int getContactId(){
        return this.contactId;
    }
}

Hibernate is running the following when the duplication happens.

SELECT contact0_.contact_id             AS contact_1_0_0_, 
       contact0_.dob                    AS dob2_0_0_, 
       contact0_.family_name            AS family_n3_0_0_, 
       contact0_.given_name             AS given_na4_0_0_, 
       contact0_.middle_name            AS middle_n5_0_0_, 
       contactema1_.contact_id          AS contact_2_0_1_, 
       contactema1_.email_address_id    AS email_ad1_1_1_, 
       contactema1_.email_address_id    AS email_ad1_1_2_, 
       contactema1_.contact_id          AS contact_2_1_2_, 
       contactema1_.email_address       AS email_ad3_1_2_, 
       contactnic2_.contact_id          AS contact_2_0_3_, 
       contactnic2_.contact_nickname_id AS contact_1_3_3_, 
       contactnic2_.contact_nickname_id AS contact_1_3_4_, 
       contactnic2_.contact_id          AS contact_2_3_4_, 
       contactnic2_.nickname            AS nickname3_3_4_ 
FROM   contact contact0_ 
       LEFT OUTER JOIN contact_email_address contactema1_ 
                    ON contact0_.contact_id = contactema1_.contact_id 
       LEFT OUTER JOIN contact_nickname contactnic2_ 
                    ON contact0_.contact_id = contactnic2_.contact_id 
WHERE  contact0_.contact_id =? 

Kind regards, Ian.

1

There are 1 answers

0
Matt On

If you never want to have duplicates in your collection, you should use Set instead of Collection in your entity.