JPA(Hibernate)问题保存了ManyToOne关系

时间:2015-05-22 20:00:26

标签: java hibernate jpa

我遇到了问题:我有一个实体定义,与DefinitionInfo实体有一个OneToMany关系,当我尝试加载现有的Definition时,向它的infoList集合添加一个DefinitionInfo,保存说它找不到我刚刚添加到Definition中的DefinitionInfo的实体。对此,我说' DUH!'我试图在定义中添加一个新的DefintionInfo,所以你当然找不到它!

以下是代码:

@Entity(name = "CohortDefinition")
@Table(name="cohort_definition")
@NamedEntityGraph(
    name = "CohortDefinition.withDetail",
    attributeNodes = { @NamedAttributeNode(value = "details", subgraph = "detailsGraph") },
    subgraphs = {@NamedSubgraph(name = "detailsGraph", type = CohortDefinitionDetails.class, attributeNodes = { @NamedAttributeNode(value="expression")})}
)
public class CohortDefinition implements Serializable{

  private static final long serialVersionUID = 1L;
...
 @OneToMany(mappedBy="cohortDefinition", fetch= FetchType.LAZY)
  private Set<CohortGenerationInfo> generationInfoList;
...
+ Getters and Setters

目标/依赖对象:

Entity(name = "CohortGenerationInfo")
@Table(name="cohort_generation_info")
public class CohortGenerationInfo implements Serializable {
  private static final long serialVersionUID = 1L;

  public  CohortGenerationInfo()
  {    
  }

  public  CohortGenerationInfo(Integer cohortDefinitionId, Integer sourceId)
  {    
    this.id = new CohortGenerationInfoPK(cohortDefinitionId, sourceId);
  }

  @EmbeddedId
  private CohortGenerationInfoPK id;

  @ManyToOne
  @MapsId("cohortDefinitionId")
  @JoinColumn(name="id")
  private CohortDefinition cohortDefinition;

这是EmbeddedID类(信息的ID包含定义的ID +代表不同类型信息的另一个实体的ID。

@Embeddable
public class CohortGenerationInfoPK implements Serializable {

  private static final long serialVersionUID = 1L;

  public CohortGenerationInfoPK() {
  }

  public CohortGenerationInfoPK(Integer cohortDefinitionId, Integer sourceId) {
    this.cohortDefinitionId = cohortDefinitionId;
    this.sourceId = sourceId;
  }

  @Column(name = "id")
  private Integer cohortDefinitionId;

  @Column(name = "source_id")
  private Integer sourceId;

+ getter/setter

这是我正在做的事情。这应该是如此简单,但我只是不明白发生了什么:

  Source source = this.getSourceRepository().findBySourceKey(sourceKey);
  CohortDefinition currentDefinition = this.cohortDefinitionRepository.findOne(id);
  CohortGenerationInfo info = findBySourceId(currentDefinition.getGenerationInfoList(), source.getSourceId());
  if (info == null)
  {
    info = new CohortGenerationInfo(currentDefinition.getId(), source.getSourceId());
    currentDefinition.getGenerationInfoList().add(info);
  }
  info.setStatus(GenerationStatus.PENDING)
    .setStartTime(Calendar.getInstance().getTime());

  this.cohortDefinitionRepository.save(currentDefinition);

这是Hibernate在爆炸之前选择的:

Hibernate: select cohortgene0_.id as id1_4_0_, cohortgene0_.source_id as source_i2_4_0_, cohortgene0_.execution_duration as executio3_4_0_, cohortgene0_.is_valid as is_valid4_4_0_, cohortgene0_.start_time as start_ti5_4_0_, cohortgene0_.status as status6_4_0_, cohortdefi1_.id as id1_2_1_, cohortdefi1_.created_by as created_2_2_1_, cohortdefi1_.created_date as created_3_2_1_, cohortdefi1_.description as descript4_2_1_, cohortdefi1_.expression_type as expressi5_2_1_, cohortdefi1_.modified_by as modified6_2_1_, cohortdefi1_.modified_date as modified7_2_1_, cohortdefi1_.name as name8_2_1_ from cohort_generation_info cohortgene0_ inner join cohort_definition cohortdefi1_ on cohortgene0_.id=cohortdefi1_.id where cohortgene0_.id=? and cohortgene0_.source_id=?

这是堆栈跟踪:

javax.persistence.EntityNotFoundException: Unable to find org.ohdsi.webapi.cohortdefinition.CohortGenerationInfo with id org.ohdsi.webapi.cohortdefinition.CohortGenerationInfoPK@3
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:183)
    at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:219)
    at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:275)
    at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:151)
    at org.hibernate.internal.SessionImpl.fireLoad(SessionImpl.java:1070)
    at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:989)
    at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:716)
    at org.hibernate.type.EntityType.resolve(EntityType.java:502)
    at org.hibernate.type.EntityType.replace(EntityType.java:366)
    at org.hibernate.type.CollectionType.replaceElements(CollectionType.java:549)
    at org.hibernate.type.CollectionType.replace(CollectionType.java:690)
    at org.hibernate.type.TypeHelper.replace(TypeHelper.java:177)
    at org.hibernate.event.internal.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:407)
    at org.hibernate.event.internal.DefaultMergeEventListener.entityIsPersistent(DefaultMergeEventListener.java:219)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:192)
    at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:85)
    at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:876)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:858)
    at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:863)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:1196)

我在堆栈跟踪的合并部分停了下来。它似乎是从数据库中获取现有实体并将其标记为mereg。定义已经存在,它只是一个新的DefinitionInfo被添加。

有没有人有任何想法?我对如何构建数据库有一些限制,但我希望这不是一个数据库结构问题,而只是一些令人讨厌的JPA。

1 个答案:

答案 0 :(得分:2)

代码存在一些明显的问题。

  1. 由于您希望进行传递持久性,即保存CohortDefinition也应该保存CohortGenerationInfo,您需要在OneToMany注释上设置级联属性。例如,
  2. @OneToMany(mappedBy="cohortDefinition", fetch= FetchType.LAZY, cascade= CascadeType.ALL)
    
    1. 您已在CohortDefinition和CohortGenerationInfo之间设置了双向关系。作为最佳实践,最好明确设置关系两侧的值,而不是依赖ORM来执行此操作。因此代码应该执行以下操作(最好将其放在辅助方法中)。
    2. currentDefinition.getGenerationInfoList().add(info);
      info.setCohortDefinition(currentDefinition);