Hibernate: many-to-many e atributos na tabela de associaçã

Olá, estou tentando fazer um relacionamento many-to-many com um atributo na tabela de join e há um erro me perseguindo. Segui a doc do Hibernate e fiz o seguinte:
Classe que representa o relacionamento com um atributo:

[code]public class RelationshipPurchaseGoods implements Serializable {

/**
 *
 */
private Goods goods;

/**
 *
 */
private int quantity;

/**
 * Returns the value of {@link #goods goods} to this object.
 *
 * @hibernate.many-to-one cascade="none"
 *                        class="br.ufpe.scacin.model.Goods"
 *                        column = "FK_GOODS_ID"
 *                        not-null="true"
 *
 * @return Returns the goods.
 */
public Goods getGoods() {
    return this.goods;
}

/**
 * Sets the value of {@link #goods} to this object.
 *
 * @param goods The goods to set.
 */
public void setGoods(Goods goods) {
    this.goods = goods;
}

/**
 * Returns the value of {@link #quantity} to this object.
 *
 * @hibernate.property column="GOODS_QUANTITY"
 *                     not-null="true"
 *                     type="int"
 *                     update="true"
 *
 * @return Returns the quantity.
 */
public int getQuantity() {
    return this.quantity;
}

/**
 * Sets the value of {@link #quantity} to this object.
 *
 * @param quantity The quantity to set.
 */
public void setQuantity(int quantity) {
    this.quantity = quantity;
}

/**
 *
 * @param obj
 * @return
 *
 * @see java.lang.Object#equals(java.lang.Object)
 */
public boolean equals(Object obj) {
    boolean result = false;

    if (obj instanceof RelationshipPurchaseGoods) {
        result = EqualsBuilder.reflectionEquals(this, obj);
    }

    return result;
}

/**
 * @return
 *
 * @see java.lang.Object#hashCode()
 */
public int hashCode() {
    return HashCodeBuilder.reflectionHashCode(this);
}

/**
 * @return
 *
 * @see java.lang.Object#toString()
 */
public String toString() {
    ToStringStyle style = ToStringStyle.MULTI_LINE_STYLE;

    return ToStringBuilder.reflectionToString(this, style);
}

}[/code]
Como o relacionamento é bidirecional, não precisei colocar um atributo Purchase nessa classe. Em Purchase, eu tenho o seguinte:

/** * Returns the value of {@link #relationships} to this object. * * @hibernate.bag cascade="save-update" * inverse="true" * lazy="true" * table="JOIN_PURCHASE_GOODS" * * @hibernate.collection-key column="FK_PURCHASE_ID" * * @hibernate.collection-composite-element * class = "br.ufpe.scacin.model.RelationshipPurchaseGoods" * * @return Returns the relationships. */ public List getRelationships() { return this.relationships; }
O que vai gerar o seguinte arquivo para mapeamento:

[code]<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
<class
name="br.ufpe.scacin.model.Purchase"
table="SCACIN_PURCHASE"
dynamic-update="false"
dynamic-insert="false"
>

    &lt;id
        name=&quot;id&quot;
        column=&quot;PURCHASE_ID&quot;
        type=&quot;long&quot;
        unsaved-value=&quot;-1&quot;
    &gt;
        &lt;generator class=&quot;native&quot;&gt;
        &lt;/generator&gt;
    &lt;/id&gt;

    &lt;many-to-one
        name=&quot;costumer&quot;
        class=&quot;br.ufpe.scacin.model.User&quot;
        cascade=&quot;none&quot;
        outer-join=&quot;auto&quot;
        update=&quot;true&quot;
        insert=&quot;true&quot;
        access=&quot;property&quot;
        column=&quot;USER_ID&quot;
        not-null=&quot;true&quot;
    /&gt;

    &lt;property
        name=&quot;date&quot;
        type=&quot;calendar&quot;
        update=&quot;true&quot;
        insert=&quot;true&quot;
        access=&quot;property&quot;
        column=&quot;PURCHASE_DATE&quot;
        not-null=&quot;true&quot;
    /&gt;

    &lt;property
        name=&quot;origin&quot;
        type=&quot;string&quot;
        update=&quot;true&quot;
        insert=&quot;true&quot;
        access=&quot;property&quot;
        column=&quot;PURCHASE_ORIGIN&quot;
        not-null=&quot;true&quot;
    /&gt;

    &lt;bag
        name=&quot;relationships&quot;
        table=&quot;JOIN_PURCHASE_GOODS&quot;
        lazy=&quot;true&quot;
        inverse=&quot;false&quot;
        cascade=&quot;all&quot;
    &gt;

          &lt;key
              column=&quot;FK_PURCHASE_ID&quot;
          &gt;
          &lt;/key&gt;

          &lt;composite-element
              class=&quot;br.ufpe.scacin.model.RelationshipPurchaseGoods&quot;
          &gt;

    &lt;many-to-one
        name=&quot;goods&quot;
        class=&quot;br.ufpe.scacin.model.Goods&quot;
        cascade=&quot;none&quot;
        outer-join=&quot;auto&quot;
        update=&quot;true&quot;
        insert=&quot;true&quot;
        access=&quot;property&quot;
        column=&quot;FK_GOODS_ID&quot;
        not-null=&quot;true&quot;
    /&gt;

    &lt;property
        name=&quot;quantity&quot;
        type=&quot;int&quot;
        update=&quot;true&quot;
        insert=&quot;true&quot;
        access=&quot;property&quot;
        column=&quot;JOIN_PURCHASE_GOODS_QUANTITY&quot;
        not-null=&quot;true&quot;
    /&gt;

          &lt;/composite-element&gt;

    &lt;/bag&gt;
&lt;/class&gt;

</hibernate-mapping>[/code]
O erro é o seguinte, o hibernate simplesmente não consegue relacionar Goods ao objeto de relacionamento e então quando tento salvar o Purchase tenho o seguinte log com o erro:

[quote]Hibernate: insert into JOIN_PURCHASE_GOODS (FK_PURCHASE_ID, FK_GOODS_ID, JOIN_PURCHASE_GOODS_QUANTITY) values (?, ?, ?)
04/08/2004 19:35:42 net.sf.hibernate.util.JDBCExceptionReporter logExceptions
WARNING: SQL Error: 1048, SQLState: S1000
04/08/2004 19:35:42 net.sf.hibernate.util.JDBCExceptionReporter logExceptions
SEVERE: General error, message from server: "Column ‘FK_GOODS_ID’ cannot be null"
04/08/2004 19:35:42 net.sf.hibernate.util.JDBCExceptionReporter logExceptions
WARNING: SQL Error: 1048, SQLState: S1000
04/08/2004 19:35:42 net.sf.hibernate.util.JDBCExceptionReporter logExceptions
SEVERE: General error, message from server: "Column ‘FK_GOODS_ID’ cannot be null"
04/08/2004 19:35:42 net.sf.hibernate.JDBCException <init>
SEVERE: Could not execute JDBC batch update
java.sql.BatchUpdateException: General error, message from server: "Column ‘FK_GOODS_ID’ cannot be null"
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1367)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeBatch(DelegatingPreparedStatement.java:231)
at net.sf.hibernate.impl.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:54)
at net.sf.hibernate.impl.BatcherImpl.executeBatch(BatcherImpl.java:122)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2417)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2371)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2236)
at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61)
at org.springframework.orm.hibernate.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:386)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:316)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:211)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:138)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:148)
at $Proxy2.insert(Unknown Source)
at br.ufpe.scacin.manager.PurchaseManager.insert(PurchaseManager.java:95)
at br.ufpe.scacin.SCACInFacade.insert(SCACInFacade.java:314)

at br.ufpe.scacin.SCACInFacade.main(SCACInFacade.java:506)
04/08/2004 19:35:42 net.sf.hibernate.impl.SessionImpl execute
SEVERE: Could not synchronize database state with session
net.sf.hibernate.JDBCException: Could not execute JDBC batch update
at net.sf.hibernate.impl.BatcherImpl.executeBatch(BatcherImpl.java:129)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2417)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2371)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2236)
at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61)
at org.springframework.orm.hibernate.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:386)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:316)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:211)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:138)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:148)
at $Proxy2.insert(Unknown Source)
at br.ufpe.scacin.manager.PurchaseManager.insert(PurchaseManager.java:95)
at br.ufpe.scacin.SCACInFacade.insert(SCACInFacade.java:314)
at br.ufpe.scacin.SCACInFacade.main(SCACInFacade.java:506)
Caused by: java.sql.BatchUpdateException: General error, message from server: "Column ‘FK_GOODS_ID’ cannot be null"
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1367)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeBatch(DelegatingPreparedStatement.java:231)
at net.sf.hibernate.impl.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:54)
at net.sf.hibernate.impl.BatcherImpl.executeBatch(BatcherImpl.java:122)
… 13 more
04/08/2004 19:35:42 org.springframework.jdbc.support.SQLStateSQLExceptionTranslator translate
INFO: Translating SQLException with SQLState ‘S1000’ and errorCode ‘1048’ and message [General error, message from server: “Column ‘FK_GOODS_ID’ cannot be null”]; SQL was [null] for task [HibernateTemplate]
org.springframework.jdbc.UncategorizedSQLException: (HibernateTemplate): encountered SQLException [General error, message from server: “Column ‘FK_GOODS_ID’ cannot be null”]; nested exception is java.sql.BatchUpdateException: General error, message from server: "Column ‘FK_GOODS_ID’ cannot be null"
java.sql.BatchUpdateException: General error, message from server: "Column ‘FK_GOODS_ID’ cannot be null"
at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1367)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeBatch(DelegatingPreparedStatement.java:231)
at net.sf.hibernate.impl.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:54)
at net.sf.hibernate.impl.BatcherImpl.executeBatch(BatcherImpl.java:122)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2417)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2371)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2236)
at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61)
at org.springframework.orm.hibernate.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:386)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:316)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:211)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:138)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:148)
at $Proxy2.insert(Unknown Source)
at br.ufpe.scacin.manager.PurchaseManager.insert(PurchaseManager.java:95)
at br.ufpe.scacin.SCACInFacade.insert(SCACInFacade.java:314)
at br.ufpe.scacin.SCACInFacade.main(SCACInFacade.java:506)[/quote]
Mais detalhes:
Hibernate 2.1.4
MySQL 4.0
Windows 2000
A DDL da tabela de join:

create table JOIN_PURCHASE_GOODS &#40; FK_PURCHASE_ID BIGINT not null, FK_GOODS_ID BIGINT not null, GOODS_QUANTITY INTEGER not null &#41;type=InnoDB;
Qualquer sugestão é muito bem vinda.

valeuz…

Oi

Jack, a documentação do Hibernate é realmente muito boa, teu problema deu o mesmo erro que o meu, hahahahahaha… Eu tb segui as DOCs e nada… Eu não sei se isso é algum problema do Hibernate, mas nunca consegui fazer many-to-many, eu sempre tenho que fazer como todos os outros SGBDs Relacionais e criar uma tabela pra acabar com o many-to-many… :(:frowning: … Se tu conseguir fazer isso funcionar posta aí a solução…

T+

Olá, Paulo, consegui fazer o esquema acima, um many-to-many com atributo, funcionar alterando… ehrm, tadã, meu test case. Ele não setava o relacionamento numa purchase e então havia um erro na hora de fazer o cascade na inserção. Bom, é isso. A doc é realmente muito boa mas algumas coisas estão meio espalhadas. Essa parte de relacionamentos, por exemplo. :wink:

ps.: se tiver bronca com many-to-many simples, avisa aê que talvez eu possa te ajudar.

valeu…