0 Replies Latest reply on Jul 30, 2006 3:13 PM by scotttam

    ManyToMany: entry on the other side of the relationship is b

    scotttam

      I have a many to many relationship that is handled by a join table. Here's the simple "diagram" :
      campaign -> campaign_adslot_xref <- ad_slot

      When I create a new campaign object and add adslots to the relationship to get the entries in the join table created, for some reason, persist is trying to create an entry in the ad_slot table when the object already exists. Therefore, I get a duplicate key exception. When I use merge instead of persist, this works fine. I know merge has a bit of overhead and checking to see if entites exist in the db but my AdSlot object is in the persistentcontext so I am not sure why it is trying to be created.

      The POJO's are:

      @Entity
      
      @Table(name="campaign")
      
      public class ParentCampaign implements Serializable {
       private long id;
      
       private Set<AdSlot> adSlots;
      
       @ManyToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY, mappedBy="campaigns")
      
       public Set<AdSlot> getAdSlots() {
      
       return adSlots;
      
       }
      
      
      
       public void setAdSlots(Set<AdSlot> adSlots) {
      
       this.adSlots = adSlots;
      
       }
      
       @Override
      
       public int hashCode() {
      
       int hash = 7;
      
       hash = 31 * hash + (int)id;
      
       hash = 31 * hash + ((null == name) ? 0 : name.hashCode());
      
       return hash;
      
       }
      
      
      
       @Override
      
       public boolean equals(Object obj) {
      
       if (obj == this) return true;
      
      
      
       if (null == obj || !(obj instanceof ParentCampaign)) {
      
       return false;
      
       }
      
      
      
       ParentCampaign other = (ParentCampaign)obj;
      
      
      
       if ((id != other.getId())) {
      
       return false;
      
       }
      
      
      
       return true;
      
       }
      
      
      }
      
      @Entity
      @Table(name="ad_slot")
      public class AdSlot implements Serializable {
       private long id;
       private Set<ParentCampaign> campaigns;
      
       @ManyToMany
       @JoinTable(name = "campaign_adslot_xref",
       joinColumns = {
       @JoinColumn(name = "ad_slot_id")
       },
       inverseJoinColumns = {
       @JoinColumn(name = "campaign_id")
       }
       )
      
       public Set<ParentCampaign> getCampaigns()
       {
       return campaigns;
       }
      
       public void setCampaigns(Set<ParentCampaign> campaigns) {
       this.campaigns = campaigns;
       }
      


      Here's where I setup the newly created Campaign object with selected AdSlots.
       if (null != selectedAdSlots && selectedAdSlots.length > 0) {
      
       for (int k=0; k < selectedAdSlots.length; k++) {
      
       AdSlot as = Utils.getAdDAO().findAdSlotLazyLoadAll(new Long(selectedAdSlots[k]));
      
      
      
       if (null == currentCampaign.getAdSlots()) {
      
       currentCampaign.setAdSlots(new HashSet<AdSlot>());
      
       }
      
      
      
       as.getCampaigns().add(currentCampaign);
      
       currentCampaign.getAdSlots().add(as);
      
       }
      
       }
      
      


      The findAdSlotLazyLoadAll looks like
       public AdSlot findAdSlotLazyLoadAll(long id) {
      
       return (AdSlot)em.createQuery("FROM AdSlot a " +
      
       "LEFT JOIN FETCH a.program " +
      
       "LEFT JOIN FETCH a.campaigns " +
      
       "WHERE a.id = :id ")
      
       .setParameter("id", id)
      
       .getSingleResult();
      
       }