views:

187

answers:

1

Hi, I'm new to Hibernate+Derby... I've seen this issue mentioned throughout the google, but have not seen a proper resolution.

This following code works fine with mysql, but when I try this on derby i get exceptions:

( each Tag has two sets of files and vise-versa - manytomany)

Tags.java

@Entity
@Table(name="TAGS")
public class Tags implements Serializable 
{

   @Id @GeneratedValue(strategy=GenerationType.AUTO)
   public long getId()
   {
      return id;
   }

   @ManyToMany(targetEntity=Files.class
   )
   @ForeignKey(name="USER_TAGS_FILES",inverseName="USER_FILES_TAGS")
   @JoinTable(name="USERTAGS_FILES",
         joinColumns=@JoinColumn(name="TAGS_ID"),
         inverseJoinColumns=@JoinColumn(name="FILES_ID"))
         public Set<data.Files> getUserFiles()
         {
      return userFiles;
         }

   @ManyToMany(mappedBy="autoTags",
         targetEntity=data.Files.class)
         public Set<data.Files> getAutoFiles()
         {
      return autoFiles;
         }

Files.java


@Entity
@Table(name="FILES")
public class Files implements Serializable
{
   @Id @GeneratedValue(strategy=GenerationType.AUTO)
   public long getId()
   {
      return id;
   }
      @ManyToMany(mappedBy="userFiles",
         targetEntity=data.Tags.class)
   public Set getUserTags()
   {
      return userTags;
   }
   @ManyToMany(targetEntity=Tags.class
         )
         @ForeignKey(name="AUTO_FILES_TAGS",inverseName="AUTO_TAGS_FILES")
   @JoinTable(name="AUTOTAGS_FILES",
         joinColumns=@JoinColumn(name="FILES_ID"),
         inverseJoinColumns=@JoinColumn(name="TAGS_ID"))
   public Set getAutoTags()
   {
      return autoTags;
   }

I add some data to the DB, but when running over Derby these exception turn up (the don't using mysql)

Exceptions


SEVERE: DELETE on table 'FILES' caused a violation of foreign key constraint 'USER_FILES_TAGS' for key (3).  The statement has been rolled back.
Jun 10, 2010 9:49:52 AM org.hibernate.event.def.AbstractFlushingEventListener performExecutions
SEVERE: Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: could not delete: [data.Files#3]
   at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
   at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
   at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2712)
   at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2895)
   at org.hibernate.action.EntityDeleteAction.execute(EntityDeleteAction.java:97)
   at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:268)
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:260)
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:184)
   at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
   at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
   at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
   at java.lang.reflect.Method.invoke(Method.java:613)
   at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:344)
   at $Proxy13.flush(Unknown Source)
   at data.HibernateORM.removeFile(HibernateORM.java:285)
   at data.DataImp.removeFile(DataImp.java:195)
   at booting.DemoBootForTestUntilTestClassesExist.main(DemoBootForTestUntilTestClassesExist.java:62)

I have never used derby before so maybe there is something crutal that i'm missing
1) what am I doing wrong?
2) is there any way of cascading properly when I have 2 many-to-many relationships between two classes?

Thanks!

+1  A: 

This following code works fine with MySQL, but when I try this on derby I get exceptions:

My guess is that you weren't using referential integrity with MySQL (i.e. not the InnoDB engine) so the constraint violation wasn't "triggered". But the error is there.

And actually, the problem is that you should put the mappedBy on the same side of the bi-directional associations, for example on Tags for both ManyToMany (and remove it from Files):

@Entity
public class Tags implements Serializable {

    @ManyToMany(mappedBy = "userTags")
    @ForeignKey(name = "USER_TAGS_FILES", inverseName = "USER_FILES_TAGS")
    @JoinTable(name = "USERTAGS_FILES", joinColumns = @JoinColumn(name = "TAGS_ID"), inverseJoinColumns = @JoinColumn(name = "FILES_ID"))
    public Set<Files> getUserFiles() {
        return userFiles;
    }

    @ManyToMany(mappedBy = "autoTags")
    public Set<Files> getAutoFiles() {
        return autoFiles;
    }

    //...
}

And Files becomes:

@Entity
public class Files implements Serializable {

    @ManyToMany
    public Set<Tags> getUserTags() {
        return userTags;
    }

    @ManyToMany
    @ForeignKey(name = "AUTO_FILES_TAGS", inverseName = "AUTO_TAGS_FILES")
    @JoinTable(name = "AUTOTAGS_FILES", joinColumns = @JoinColumn(name = "FILES_ID"), inverseJoinColumns = @JoinColumn(name = "TAGS_ID"))
    public Set<Tags> getAutoTags() {
        return autoTags;
    }

    // ...
}

With these changes, the following test passes (the session is created outside the test method):

@Test
public void removeFiles() {
    Files files = (Files) session.get(Files.class, 1L);

    session.delete(files);
    session.flush();

    Query q = session.createQuery("from Files f where f.id = :id");
    q.setParameter("id", 1l);
    Files result = (Files) q.uniqueResult();
    assertNull(result);
}

And generates the following queries:

Hibernate: select files0_.id as id100_0_ from Files files0_ where files0_.id=?
Hibernate: delete from AUTOTAGS_FILES where FILES_ID=?
Hibernate: delete from Files_TAGS where userFiles_id=?
Hibernate: delete from Files where id=?
Hibernate: select files0_.id as id100_ from Files files0_ where files0_.id=?

Tested with Derby.

Pascal Thivent
your example has not added any tags to the Files objectIf you were to add the following code, i reckon you would still get the excetpion (as it is for me)Tags tags=(Tags)session.get(Tags.class,1L);tags.getUserFiles().add(files); it should still generate the same exception
msshapira
@msshapira: 1. Fix the mapping as suggested 2. Provide your code as REQUESTED, I won't help further without seeing your code (and fixed mappings).
Pascal Thivent
@Pascal Thivent I fixed it with a much simpler way, I didn't know that when deleting with manytomany I must nullify the sets to remove the constraints. thanks for your help
msshapira