-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: Finding a good way to delete elems from manytomany relation
PostPosted: Wed Mar 19, 2008 11:21 am 
Newbie

Joined: Thu Feb 21, 2008 8:39 am
Posts: 15
I have a many to many relation, map as the DATABASE SCHEMA (see below) describes.
In the database, I have three tables, one for clients, one for products, the last one (called sells) is to implement the MxN relation among clients and products.
In the java side, I have also three classes to map the above three tables. See JAVA DEFINITION CODE.
I map the middle class with a composite id where each id is a key-many-to-one, that targets to the associated class (products and clients). The mapping is described in XML DEFINITION CODE.
The way I work adding and removing sells to the client is the following:

Adding sells:
Code:
       ClientBean client = new ClientBean("Albert");
       session.saveOrUpdate(client);       
       //article
       ProductBean article = new ProductBean("headache");
       article.setDescription("headache");
       session.save(article);       
       //Sells
       Sells sells = new Sells(article,client,"11-11-1111");
           
       client.getSells().add(sells);


In this case I create a client and a product, just for the example, this creation it will not be needed later. To create the relation, I create a sells element, initializing the article and client, and I just add the new sell to the client. Hibernate will create a row in the relation table.
I'm really new in hibernate and I don't know if this is the best way to work with NxM relations, any comments? , working like this is quite comfortable.
The main problem is deleting the elements.

This is what I do:
Code:
       
        Query query = session.createQuery("from Sells s where s.id.client.name = ?");
        query.setString(0, "Albert");
        Iterator articlesFromClient = query.list().iterator();
       
        while (articlesFromClient.hasNext()) {
            Sells object = (Sells) articlesFromClient.next();
            System.out.println(object.getId().getProduct().getDescription());
            articlesFromClient.remove();
        }

What I do to delete is query all the relations and delete the relation among the client and the product.
Working like this is not really comfortable, but is the only way, until now, I found to delete this relation.

What I would like to do is just remove the element from the client collection and let hibernate delete the relation, see following code:
Code:

        Query query = session.createQuery("from ClientBean c where c.name = ?");
        query.setString(0, "Albert"); 
        ClientBean c = (ClientBean) query.uniqueResult();
       
        //session.delete(c);
        Iterator<Sells> sellsIterator = c.getSells().iterator();
        while (sellsIterator.hasNext()) {
            Sells sells2 = (Sells) sellsIterator.next();
            System.out.println(sells2.getData());
            sellsIterator.remove();
        }

The problem with the above approach is that when it is executed, hibernate, instead of deleting the relation with the client tries to update the it, telling
to the database that row has a field null. The database tells hibernate that this update is not possible due to this field is part of a primary key and can't be null.

Here is the error:

Hibernate: update CLIENTS_has_PRODUCTS set CLIENT_ID=null where CLIENT_ID=?
15:52:40,476 WARN JDBCExceptionReporter:77 - SQL Error: 1048, SQLState: 23000
15:52:40,476 ERROR JDBCExceptionReporter:78 - Column 'CLIENT_ID' cannot be null

Any solutions to force hibernate to delete the row instead of updating it?.(I already tried to remove the relation from client and product and after commit, but same error)

Sorry for this long and boring explanation.

ADDITIONAL CODE:

DATABASE SCHEMA:

Code:
DROP DATABASE IF EXISTS sells;
CREATE DATABASE sells;
USE sells;

CREATE TABLE PRODUCT (
  ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  DESCRIPTION Varchar(45) NULL,
  PRIMARY KEY(ID)
);

CREATE TABLE CLIENT (
  ID INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  NAME Varchar(45) NULL,
  PRIMARY KEY(ID)
);

CREATE TABLE CLIENTS_has_PRODUCTS (
  CLIENT_ID INTEGER UNSIGNED,
  PRODUCT_ID INTEGER UNSIGNED,
  DATA Varchar(45) NULL,
  PRIMARY KEY(CLIENT_ID,PRODUCT_ID),
  FOREIGN KEY(CLIENT_ID)
    REFERENCES CLIENT(ID),
  FOREIGN KEY(PRODUCT_ID)
    REFERENCES PRODUCT(ID)
);


JAVA DEFINITION CODE:

Code:

public class ClientBean {
    private int id=0;   
    private String name;
    private Set sells;   //Objects Type hibernate_beans.Sells   
   
    public ClientBean(String name) {
        super();
        this.name = name;
        this.sells = new HashSet();
    }
    ...getters and setter...
}

public class ProductBean {
    private int id=0;
    private String description;
    private Set sells; //Objects Type hibernate_beans.Sells
   
    public ProductBean(String description) {
        this.description = description;
        this.sells = new HashSet();
    }   
       
    public ProductBean() {
    }
        ...getters and setters....
}


public class Sells implements Serializable{
   
    public static class SellsID implements Serializable{
        private ProductBean product=null;
        private ClientBean client=null;

        public SellsID(){}
       
        public SellsID(ProductBean product, ClientBean client) {
            super();
            this.product = product;
            this.client = client;
        }
                ...getters and setters....
    }     
   
    private SellsID id = new SellsID();

    public Sells(){}
   
    public Sells(ProductBean article, ClientBean client, String data) {
        super();
        this.id = new SellsID(article,client);
        this.data = data;
    }   
   
    private String data = null;
   
   
    @Override
    public boolean equals(Object obj) {
        if(obj instanceof Sells){
            Sells s = (Sells) obj;
            if((s.getId().getProduct().getId() == this.getId().getProduct().getId())
                        &&
               (s.getId().getClient().getId() == this.getId().getClient().getId())                   
               ) return true;
            else
                return false;
           
        }else return false;       
        ....getters and setters....
    }


XML DEFINITION CODE
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-lazy="false">
   
    <!--ClientBean-->   
    <class name="hibernate_beans.ClientBean" table="CLIENT">
        <id name="id" type="int" column="ID" unsaved-value="0">
            <generator class="native"/>
        </id>       
        <property name="name" type="string" column="NAME"/>
       
        <set name="sells" inverse="false" lazy="true" cascade="all">
            <key column="CLIENT_ID"/>
            <one-to-many class="hibernate_beans.Sells"/>
        </set>
       
    </class>
   
    <!--ArticleBean-->   
    <class name="hibernate_beans.ProductBean" table="PRODUCT">
        <id name="id" type="int" column="ID" unsaved-value="0">
            <generator class="native"/>
        </id>       
        <property name="description" type="string" column="DESCRIPTION"/>
        <set name="sells" inverse="false" lazy="true" cascade="all">
            <key column="PRODUCT_ID"/>
            <one-to-many class="hibernate_beans.Sells"/>
        </set>
    </class>   
       
   <class name="hibernate_beans.Sells" table="CLIENTS_has_PRODUCTS">     
        <composite-id name="id" class="hibernate_beans.Sells$SellsID">
            <key-many-to-one name="product" class="hibernate_beans.ProductBean" column="PRODUCT_ID" access="field"/>
            <key-many-to-one name="client" class="hibernate_beans.ClientBean" column="CLIENT_ID" access="field"/>
        </composite-id>
             
      <property name="data" type="string" column="DATA"/>

   </class>       
       
</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 27, 2008 3:11 am 
Newbie

Joined: Thu Feb 21, 2008 8:39 am
Posts: 15
Anybody worked with many-to-many relation? Or maybe the post is too long?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Mar 27, 2008 9:11 am 
Newbie

Joined: Wed Mar 26, 2008 9:04 am
Posts: 9
Location: Athens, Greece
Hello,

Im as well new to hibernate but I read something which might be usefull.
I think your problem might be caused by the fact that your ClientBean/ArticleBean are responsible for the connection (inverse=false)

That means that changes to them have to be reflected with updates on Sells.
Maybe its enough to specify inverse=""true" and cascade="all-delete-orphan"

Hope this helps,

Arne


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 31, 2008 4:01 am 
Newbie

Joined: Thu Feb 21, 2008 8:39 am
Posts: 15
First of all, thanks for the given help and support.

cascade='all-delete-orphan' has the same effect as cascade='all' here.

What I do is to configure the clients and articles to be responsible for the link with the Sells class, when I add or remove elements hibernate updates that changes to the database Sells table, that is exactly what I want.

The problem is that when I remove a Sell from ClientBean and ArticleBean, hibernate should delete that Sell, but it does not. Instead of deleting the Sell, hibernate frist does and update (to NULL) of the foreign keys, of Sells, that points to ClientBean and ArticleBean, but database does not let hibernate to do that, because this two foreign keys together compose a primary key, (see database creation script).

My main problem is that I don't know how to tell hibernate to delete this row instead of updating it.

Any idea?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 31, 2008 8:20 am 
Regular
Regular

Joined: Thu Mar 06, 2008 5:06 am
Posts: 68
specify inverse="true" in the set "sells"


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 31, 2008 9:27 am 
Newbie

Joined: Thu Feb 21, 2008 8:39 am
Posts: 15
You are right, if the set where I remove the item is not set to inverse=true the item is not deleted, just updated.

Thanks a lot to both of you.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.