n:m与Hibernate中的附加信息的关系

时间:2012-01-09 11:45:42

标签: java hibernate orm entity-relationship

我在Hibernate中遇到了关系问题。

场景:我有2个实体'任务'和'资源'。每个“任务”可以有多个“资源”,每个“资源”可以有多个“任务”。因此关系是n:m-Relation。在关系表中,我需要一个“资源”类型的附加列,因为“资源”可以在“任务”中有不同的角色。

我找到了一些带有额外列的连接表的示例,并尝试以这种方式实现它。示例:http://www.mkyong.com/hibernate/hibernate-many-to-many-example-join-table-extra-column-annotation/

问题: 当我删除与'Resource'关联的'Task'时,javax.persistence.EntityNotFoundException:已传递给persist的已删除实体:[...]被抛出。

现在我的问题: '连接表有额外列'是处理这种情况的最佳方法吗?或者,对于“资源”可以拥有的每个角色,使用简单的ManyToMany(@JoinTable)关系会更好吗? 例如:当有4个角色时,“任务”和“资源”之间会有4个不同的关系表。

以下例外的原因是什么?

‘javax.persistence.EntityNotFoundException: deleted entity passed to persist: […]’

编辑:

deleted entity passed to persist: [com.domain.Task# ]
    org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1369)
    org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1315)
    org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:81)
    org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:467)
    org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    $Proxy43.deleteVorgaenge(Unknown Source)
    com.service.locklayers.TaskLockService.deleteTasks(TaskLockService.java:364)
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    java.lang.reflect.Method.invoke(Method.java:597)
    sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:303)
    sun.rmi.transport.Transport$1.run(Transport.java:159)
    java.security.AccessController.doPrivileged(Native Method)
    sun.rmi.transport.Transport.serviceCall(Transport.java:155)
    sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
    sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
    sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
    java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    java.lang.Thread.run(Thread.java:662)

以下是涉及的课程......

@Entity
@Table( name = "task" )
public class Task implements Serializable
{
  @Id
  @GeneratedValue( strategy = GenerationType.IDENTITY )
  @Column( name = "task_id" )
  private int         taskId;

  private String      name;

  @OneToMany( fetch = FetchType.EAGER, mappedBy = "taskFk", cascade = CascadeType.ALL )
  Set<TaskZuResource> taskZuResourceList = new HashSet<TaskZuResource>();

  public int getId()
  {
    return taskId;
  }
}

@Entity
@Table( name = "resource" )
public class Resource implements Serializable
{
  @Id
  @GeneratedValue( strategy = GenerationType.IDENTITY )
  @Column( name = "resource_id" )
  private int         resourceId;

  private String      name;


  @OneToMany( mappedBy = "resourceFk", fetch = FetchType.EAGER, cascade = CascadeType.ALL )
  Set<TaskZuResource> taskZuResourceList = new HashSet<TaskZuResource>();

  public int getId()
  {
    return resourceId;
  }
}

@Entity
@Table( name = "task_zu_resource" )
public class TaskZuResource implements Serializable
{
  @EmbeddedId
  private TaskZuResourceId pk;

  @MapsId( "taskFk" )
  @ManyToOne( optional = false, fetch = FetchType.EAGER )
  @JoinColumn( name = "task_fk" )
  private Task                 taskFk;

  @MapsId( "resourceFk" )
  @ManyToOne( optional = false, fetch = FetchType.EAGER )
  @JoinColumn( name = "resource_fk" )
  private Resource             resourceFk;

  public TaskZuResource()
  {
  }

  public TaskZuResource( Task taskFk, Resource resourceFk, int resourcenArt )
  {
    this.taskFk = taskFk;
    this.resourceFk = resourceFk;

    pk = new TaskZuResourceId( taskFk.getId(), resourceFk.getId(), resourcenArt );
  }


  public TaskZuResourceId getPk()
  {
    return pk;
  }

  public void setPk( TaskZuResourceId pk )
  {
    this.pk = pk;
  }


  public Task getTaskFk()
  {
    return taskFk;
  }

  public void setTaskFk( Task taskFk )
  {
    this.taskFk = taskFk;
  }

  public Resource getResourceFk()
  {
    return resourceFk;
  }

  public void setResourceFk( Resource resourceFk )
  {
    this.resourceFk = resourceFk;
  }


  @Transient
  public int getResourcenType()
  {
    return getPk().getResourcenType();
  }


  public void setResourcenType( int resourcenArt )
  {
    getPk().setResourcenType( resourcenArt );
  }

  @Override
  public int hashCode()
  {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((pk == null) ? 0 : pk.hashCode());
    result = prime * result + ((resourceFk == null) ? 0 : resourceFk.hashCode());
    result = prime * result + ((taskFk == null) ? 0 : taskFk.hashCode());
    return result;
  }

  @Override
  public boolean equals( Object obj )
  {
    if ( this == obj )
      return true;
    if ( obj == null )
      return false;
    if ( getClass() != obj.getClass() )
      return false;
    TaskZuResource other = (TaskZuResource) obj;
    if ( pk == null )
    {
      if ( other.pk != null )
        return false;
    }
    else
      if ( !pk.equals( other.pk ) )
        return false;
    if ( resourceFk == null )
    {
      if ( other.resourceFk != null )
        return false;
    }
    else
      if ( !resourceFk.equals( other.resourceFk ) )
        return false;
    if ( taskFk == null )
    {
      if ( other.taskFk != null )
        return false;
    }
    else
      if ( !taskFk.equals( other.taskFk ) )
        return false;
    return true;
  }

}

@Embeddable
public class TaskZuResourceId implements Serializable
{
  private int taskFk;
  private int resourceFk;

  @Column( name = "resourcen_type" )
  private int resourcenType;

  public TaskZuResourceId()
  {
  }

  public TaskZuResourceId( int taskFk, int resourceFk, int resourcenType )
  {
    this.taskFk = taskFk;
    this.resourceFk = resourceFk;
    this.resourcenType = resourcenType;
  }

  public int getTaskFk()
  {
    return taskFk;
  }

  public void setTaskFk( int taskFk )
  {
    this.taskFk = taskFk;
  }

  public int getResourceFk()
  {
    return resourceFk;
  }

  public void setResourceFk( int resourceFk )
  {
    this.resourceFk = resourceFk;
  }

  public int getResourcenType()
  {
    return resourcenType;
  }

  public void setResourcenType( int resourcenType )
  {
    this.resourcenType = resourcenType;
  }

  @Override
  public int hashCode()
  {
    final int prime = 31;
    int result = 1;
    result = prime * result + resourceFk;
    result = prime * result + resourcenType;
    result = prime * result + taskFk;
    return result;
  }

  @Override
  public boolean equals( Object obj )
  {
    if ( this == obj )
      return true;
    if ( obj == null )
      return false;
    if ( getClass() != obj.getClass() )
      return false;
    TaskZuResourceId other = (TaskZuResourceId) obj;
    if ( resourceFk != other.resourceFk )
      return false;
    if ( resourcenType != other.resourcenType )
      return false;
    if ( taskFk != other.taskFk )
      return false;
    return true;
  }
}

THX

1 个答案:

答案 0 :(得分:1)

听起来你仍然有对已删除实体的引用。例如,删除Task对象,但仍有一个TaskResource对象引用已删除的任务。

如果这是问题,那么在您删除任务后,您可以尝试使用taskResource.setTaskFk(null)之类的内容删除悬空参考。