-->
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: Trouble w. many-to-many association and on-delete="casc
PostPosted: Tue Oct 04, 2005 5:16 am 
Newbie

Joined: Tue Oct 04, 2005 2:19 am
Posts: 2
I use a biderectional many-to-many association and for the key i have set on-delete="cascade" on both ends.

What i expect is that the generated schema contains on delete cascade
foreign key definitions for both ends but this is missing for the invers end.

I want to get the behaviour that when an object of the invers end is deleted
the associations in the linktable are deleted too.

I want this behaviour independent if i delete the object of the invers
end via
Code:
session.delete(DAO)

or via bulk DML-style operation
Code:
  Query q=session.createQuery("delete from ProfileDAO where name like :arg");
  q.setString("arg","prof%"); 
  q.executeUpdate();


Questions:
Is this incomplete schema a bug or did i completely misunderstood the usage ?
Is there something to be considered when using DML-style operations
as described in chapter 14.4 in conjunction with on-delete="cascade"
foreign keys ?
When manipulating the DB with this bulk DML-style operations is the
caching of hibernate aware of this modifications ?

Hibernate version:
3.1 beta 2
Java 1.5.0_04, JBoss 4.0.3RC2

Generted schema (missing on delete cascade on inverse end):
alter table SXUSER_SXPROFILE drop foreign key fk_profile2user;
alter table SXUSER_SXPROFILE drop foreign key fk_user2profile;
drop table if exists SXPROFILE;
drop table if exists SXUSER;
drop table if exists SXUSER_SXPROFILE;
create table SXPROFILE (id integer not null auto_increment, name varchar(30) not null unique, primary key (id)) type=InnoDB;
create table SXUSER (id integer not null auto_increment, loginname varchar(20) not null unique, firstname varchar(30), lastname varchar(40), locked bit not null, pwd varchar(30), primary key (id)) type=InnoDB;
create table SXUSER_SXPROFILE (profile_id integer not null, user_id integer not null, primary key (user_id, profile_id)) type=InnoDB;
alter table SXUSER_SXPROFILE add index fk_profile2user (user_id), add constraint fk_profile2user foreign key (user_id) references SXUSER (id) on delete cascade;
alter table SXUSER_SXPROFILE add index fk_user2profile (profile_id), add constraint fk_user2profile foreign key (profile_id) references SXPROFILE (id);


Attempt of correction:

I have debugged the SchemaGeneration.

Following code change in the HbmBinder.java source (of hibernate3.jar)
solves the schema generation but on startup i got an
org.hibernate.MappingException: only inverse one-to-many associations may use on-delete="cascade"

HbmBinder.java Line 2309-2311
Code:
  else if ( "many-to-many".equals( name ) ) {
    ManyToOne element = new ManyToOne( collection.getCollectionTable() );
    collection.setElement( element );


changed to

Code:
  else if ( "many-to-many".equals( name ) ) {
    ManyToOne element = new ManyToOne( collection.getCollectionTable() );
    KeyValue keyVal = collection.getKey();
    if ((keyVal != null) && (keyVal instanceof SimpleValue)) {
      element.setCascadeDeleteEnabled(((SimpleValue)keyVal).isCascadeDeleteEnabled());
    }
    collection.setElement( element );



Mapping documents:

<hibernate-mapping
>
<class
name="demo.UserDataDAO"
table="SXUSER"
polymorphism="explicit"
dynamic-update="true"
>
<cache usage="read-write" />

<id
name="id"
column="id"
type="java.lang.Integer"
>
<generator class="native">
<param name="sequence">userdataid_seq</param>
</generator>
</id>

<property
name="loginname"
type="java.lang.String"
update="true"
insert="true"
column="loginname"
length="20"
not-null="true"
unique="true"
/>

<property
name="firstname"
type="java.lang.String"
update="true"
insert="true"
column="firstname"
length="30"
/>

<property
name="lastname"
type="java.lang.String"
update="true"
insert="true"
column="lastname"
length="40"
/>

<property
name="locked"
type="boolean"
update="true"
insert="true"
column="locked"
not-null="true"
/>

<property
name="pwd"
type="java.lang.String"
update="true"
insert="true"
column="pwd"
length="30"
/>

<set
name="profiles"
table="SXUSER_SXPROFILE"
lazy="true"
cascade="save-update"
sort="unsorted"
>

<key
column="user_id"
on-delete="cascade"
foreign-key="fk_profile2user"
>
</key>

<many-to-many
class="demo.ProfileDAO"
column="profile_id"
outer-join="auto"
foreign-key="fk_user2profile"
/>

</set>
</class>

<class
name="demo.ProfileDAO"
table="SXPROFILE"
polymorphism="explicit"
dynamic-update="true"
>
<cache usage="read-write" />

<id
name="id"
column="id"
type="java.lang.Integer"
>
<generator class="native">
<param name="sequence">profileid_seq</param>
</generator>
</id>

<property
name="name"
type="java.lang.String"
update="true"
insert="true"
column="name"
length="30"
not-null="true"
unique="true"
/>

<set
name="users"
table="SXUSER_SXPROFILE"
lazy="true"
inverse="true"
cascade="save-update"
sort="unsorted"
>

<key
column="profile_id"
on-delete="cascade"
foreign-key="fk_user2profile"
>
</key>

<many-to-many
class="demo.UserDataDAO"
column="user_id"
outer-join="auto"
foreign-key="fk_profile2user"
/>

</set>

</class>

</hibernate-mapping>


Name and version of the database you are using:
MySQL 4.1.5 with MySQLInnoDBDialect and Oracle10 with Oracle9Dialect

The generated SQL (show_sql=true):

Exception stackdump:

org.hibernate.MappingException: only inverse one-to-many associations may use on-delete="cascade": demo.ProfileDAO.users
at org.hibernate.mapping.Collection.validate(Collection.java:238)
at org.hibernate.mapping.Set.validate(Set.java:19)
at org.hibernate.cfg.Configuration.validate(Configuration.java:935)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1095)
at org.jboss.hibernate.jmx.Hibernate.buildSessionFactory(Hibernate.java:239)
at org.jboss.hibernate.jmx.Hibernate.startService(Hibernate.java:130)
at org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:287)
at org.jboss.system.ServiceMBeanSupport.jbossInternalLifecycle(ServiceMBeanSupport.java:236)
at sun.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:141)
at org.jboss.mx.server.Invocation.dispatch(Invocation.java:80)
at org.jboss.mx.server.Invocation.invoke(Invocation.java:72)
at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:245)
at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:644)
at org.jboss.system.ServiceController$ServiceProxy.invoke(ServiceController.java:974)
at $Proxy0.start(Unknown Source)
at org.jboss.system.ServiceController.start(ServiceController.java:453)
at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 04, 2005 6:17 am 
Beginner
Beginner

Joined: Mon Sep 22, 2003 5:18 am
Posts: 28
You need to decide which side of many-to-many assosiation will actually be the primary and use cascading for that end of relationship. The 'invers' attribute designates the 'passive' side of relationship, all chagnes to which will be ignore by hibernate.
Why do you need to be able to remove entities from the 'inversed' side of relationship?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 04, 2005 6:54 am 
Newbie

Joined: Tue Oct 04, 2005 2:19 am
Posts: 2
Consider you have two Entities (e.g. Person and VisitedCity) with equal priority.
You want to create/modify/delete these Entities. Further you want to
search for these entities by specifying wildcards for some of their properties. And you also want to execute bulk operations to delete
several rows of an entity by specifying wildcards for some of their properties.

Additional these Entities have a bidirectional many-to-many association.

So, why not deleting objects from the inverse side.


I want to delete unloaded objects from the inverse side via bulk DML-style
operation. I want to address the objects by specifying some criteria for their properties.

I don't want to load this objects into memory because they are maybe several 100000.

The bulk DML-style operation didn't handle the association.
Therefore, to avoid the DB integrity constraint violation, i wan't to use the
on delete cascade foreign key of the DB.


Top
 Profile  
 
 Post subject: replacing many-to-many with 2x one-to-many
PostPosted: Mon May 21, 2007 6:02 pm 
Newbie

Joined: Tue Feb 14, 2006 5:13 am
Posts: 18
i just stumbled across the same problem: i have the requirement to be able to use on-delete cascade on both sides of a many-to-many join table and couldn't find a way (using hibernate annotations)

so i replaced the many-to-many associations with an "association entity" that has a composite key containing two many-to-one associations pointing to the two associated entities.
now i could use the @OnDelete for the inverse side of the association in my entities.

Code:
@Entity
class A {
  @OneToMany( mappedBy="key.b" )
  @OnDelete(action=OnDeleteAction.CASCADE)
  List<ABAssoc> refs;
}

@Entity
class B {
  @OneToMany( mappedBy="key.a" )
  @OnDelete(action=OnDeleteAction.CASCADE)
  List<ABAssoc> refs;
}

@Embeddable
class Key {
  @ManyToOne
  A a;
  @ManyToOne
  B b;
}

@Entity
class ABAssoc {
  @Id
  Key key;
}



although this works, it makes working with the many-to-many association a pain: instead of just creating new associations by adding the related objects to their corresponding lists, i have to fiddle arround with these association entities: i have to create and delete instances to be able to add/remove associations. this requires to have access to my dao-implementations, which in turn forces me to move the code out of the entities. and since Key is the @Id of ABAssoc i'm not able to change only one side of such an association (e.g. replace one B instance with another) without deleting the old ABAssoc instance and creating a new one.

all this makes my code quite complex compared to the old many-to-many solution.

so if anybody knows a way to use hibernate's many-to-many associations with OnDelete on both sides, i would be glad to read about it.

Thanks in advance,
andi


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 24, 2007 12:58 pm 
Newbie

Joined: Tue Feb 14, 2006 5:13 am
Posts: 18
maybe someone with deeper knowledge of hibernate can answer this:

is the missing opportunity to set the on-delete contraint on many-to-many associations just a missing configuration option, or are there techical reasons in hibernate's implementation that don't allow on-delete on many-to-many.

so should i expect trouble if i manually include the on-delete-constraint in hibernate's db-schema and continue to use hibernate's regular many-to-many associations?

any hint is welcome!

thanks in advance,
andi


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 15, 2007 12:48 pm 
Newbie

Joined: Sun Jul 15, 2007 12:35 pm
Posts: 1
I met this problem too. Since the association table contains association info, it is natural thought that delete of either side will cause the deletion of corresponding association entry. Then why is this impossible?

Can any one help me on this issue?

Hope hibernate support team members like emmanuel could see this and give me some clue :D


Any help or advice is greatly appreciated!!


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:
cron
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.