6 Replies Latest reply on May 6, 2005 9:26 PM by anupama24

    @ManyToMany: Howto delete associations ?

    elkner

      Does anybody know, how to remove a ManyToMany relationship ?

      I've experimented with the follwoing case:

      @Entity
      @Table (name="products")
      public class A_Product implements Serializable {
       private int id;
      
       A_Product() {}
      
       @Column (name ="products_id", nullable=false)
       @Id(generate = GeneratorType.IDENTITY)
       public int getId() { id }
       void setId(int id) { this.id = id; }
      
       @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE},
       fetch = FetchType.LAZY, mappedBy="products")
       public Collection<A_Category> getCategories() { return categories; }
      
       void setCategories(Collection<A_Category> categories) { this.categories = categories; }
       }
      
      @Entity
      @Table(name="categories")
      public class A_Category implements Serializable {
       private int id;
       @Id(generate = GeneratorType.IDENTITY)
       @Column(name="categories_id", nullable=false)
       public int getId() { return this.id; }
       public void setId(int id) { this.id = id; }
      
       @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE },
       fetch = FetchType.EAGER)
       @AssociationTable(table = @Table(name="products_to_categories"),
       joinColumns = {
       @JoinColumn(name="categories_id", referencedColumnName="categories_id")
       },
       inverseJoinColumns = {
       @JoinColumn(name="products_id", referencedColumnName="products_id")
       })
       public Collection<A_Product> getProducts() { return products; }
       void setProducts(Collection<A_Product> products) { this.products = products; }
      }
      
      @Stateless
      class ProductManager {
       @Inject
       private EntityManager manager;
       // ...
       @TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
       public void delete(A_Product product, String clientID) {
       if (product == null) { return false; }
       manager.refresh(product);
       Collection<A_Category> cats = product.getCategories();
       for (A_Category c : cats) {
       c.getProducts().remove(product);
       manager.merge(c);
       }
       manager.remove(product);
       }
      }
      


      But unfortunately, this doesn't work :(. So I'tried to directly manipulate the assoc. table with
      Query q = manager.createQuery("DELETE FROM products_to_categories ptc "
       + "WHERE ptc.products_id=:id").setParameter("id", product.getId());
       q.executeUpdate();
      

      but here I get an "unsupported" exception.

      So how can one remove a relationship from the association table (cascading.all is obviously not possible)?

        • 1. Re: @ManyToMany: Howto delete associations ?
          epbernard

          #1 should work even if the merge is unecessary. What is the problem with that one. Are your equals implementations OK?

          • 2. Re: @ManyToMany: Howto delete associations ?
            elkner

             

            "epbernard" wrote:
            #1 should work even if the merge is unecessary. What is the problem with that one.


            E.g. the assoc. table has the follwoing content:
            categories_id | products_id
            --------------+------------
             100 | 1
             100 | 2
             100 | 3
             200 | 5
             200 | 1
            


            Cascade delete products -> categories: if product 1 gets removed, categories 100 and 200 would be removed as well -> disaster.
            Cascade.delete categories -> products: if category 100 gets removed, products 1,2,3 will be removed as well, but product 1 is still part of category 200 -> disaster.
            So cascade.delete can not be used on any side.

            So (even that it is probably inefficient) I tried approach #1, but nothing gets deleted in the assoc. table :(

            "epbernard" wrote:
            Are your equals implementations OK?


            Good point. At the moment I have equals() and hashCode() defined for PKs, only.
            Perhaps I would implement equals() for entities as well (if required), but at the moment 4me it is absolutely unclear, when and how it would be used by jboss/hibernate.

            E.g. usually equals would mean "if all fields have an value which is equal to the appropriate field in the other object". But using this rule, I'm not sure, whether hibernate starts to generate new entities if a field changes (even if the PK is the same) or which other side effects it would have. Actually wrt. DBs I would implement equals() as 'obj1.id == obj2.id', but somewhere I read, that one shouldn't do that.

            So the problem is, where can I find something, which explains, how equals() should be used wrt. entites, since one must probably implement entity.equals() different than a normal object.equals() ? ...

            • 3. Re: @ManyToMany: Howto delete associations ?
              epbernard
              • 4. Re: @ManyToMany: Howto delete associations ?
                sonofseven

                hi elkner

                did you get it working?

                thanks
                rp

                • 5. Re: @ManyToMany: Howto delete associations ?
                  elkner

                   

                  "SonOfSeven" wrote:
                  did you get it working?


                  Yes (but seems to be very inefficient). Note: I've changed all *To* to be LAZY:

                   @TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
                   public void delete(A_Product product, String clientID) {
                   if (product == null) {
                   return false;
                   }
                   manager.refresh(product);
                   manager.createQuery("FROM A_Product p LEFT JOIN FETCH p.categories "
                   + "WHERE p.id=" + product.getId()).getResultList();
                   Collection<A_Category> cats = product.getCategories();
                   for (A_Category c : cats) {
                   manager.createQuery("FROM A_Category c LEFT JOIN FETCH c.products "
                   + "WHERE c.id=" + c.getId()).getResultList();
                   c.getProducts().remove(product);
                   }
                   manager.remove(product);
                   }
                  


                  • 6. Re: @ManyToMany: Howto delete associations ?
                    anupama24

                    Was trying something similar. (using preview 3)

                    I got org.hibernate.MappingException: Unknown entity: org.hibernate.collection.PersistentBag, when I had the manager.merge at the end.
                    Worked fine and no problems when removed the manager.merge statement.

                    -Ana