使用Spring JpaRepository,以Hibernate 4作为提供程序,在具有复合主键的表上抛出IdentifierGenerationException

时间:2014-08-06 09:35:39

标签: java spring hibernate jpa

正如标题所说。我有一个带有复合键的实体。该实体是:

ContractServiceLocation.java

@Entity
@Table(name="CONTRACT_SERVICE_LOCATION")
@NamedQuery(name="ContractServiceLocation.findAll", query="SELECT c FROM ContractServiceLocation c")
@TypeDef(defaultForType= LocalDate.class, typeClass = LocalDateType.class)
public class ContractServiceLocation implements Serializable {
    private static final long serialVersionUID = 1L;

    @EmbeddedId
    private ContractServiceLocationPK id;

    @Column(nullable=false)
    private LocalDate datefrom;

    private LocalDate dateto;

    @Column(length=90)
    private String details;

    @Column(nullable=false, precision=65535, scale=32767)
    private BigDecimal price;

    //bi-directional many-to-one association to Contract
    @ManyToOne
    @JoinColumn(name="CONTRACT_ID", nullable=false, insertable=false, updatable=false)
    private Contract contract;

    //uni-directional many-to-one association to Location
    @ManyToOne
    @JoinColumn(name="LOCATION_ID", nullable=false, insertable=false, updatable=false)
    private Location location;

    //uni-directional many-to-one association to Service
    @ManyToOne
    @JoinColumn(name="SERVICE_ID", nullable=false, insertable=false, updatable=false)
    private Service service;

    //getters & setters
    }

ContractServiceLocationPK.java

@Embeddable
public class ContractServiceLocationPK implements Serializable {
    //default serial version id, required for serializable classes.
    private static final long serialVersionUID = 1L;

    @Column(name="CONTRACT_ID", insertable=false, updatable=false, unique=true, nullable=false)
    private long contractId;

    @Column(name="LOCATION_ID", insertable=false, updatable=false, unique=true, nullable=false)
    private long locationId;

    @Column(name="SERVICE_ID", insertable=false, updatable=false, unique=true, nullable=false)
    private long serviceId;

    //getters & setters & equals & hashcode
    }

由于我将JpaRepository用于所有其他实体,我认为它支持具有复合键的实体。所以我把Dao定义为:

ContractServiceLocationDao.java

@Repository
public interface ContractServiceLocationDao extends
        JpaRepository<ContractServiceLocation, ContractServiceLocationPK> {

}

但是,在ContractServiceLocation实体上调用save方法后,我得到一个:

org.springframework.orm.jpa.JpaSystemException: null id generated for:class hr.kingict.telco.model.ContractServiceLocation; nested exception is org.hibernate.id.IdentifierGenerationException: null id generated for:class hr.kingict.telco.model.ContractServiceLocation

我在调试中检查过所有复合键属性(合同,服务和位置)都不为空。但是例外情况说&#34; null id 为类生成 ...&#34;所以我假设它以某种方式尝试生成一个id(即使我没有设置@GeneratedValue注释)。

我该怎么做才能解决这个问题?我是否必须手动编写dao而不是依赖JpaRepository?

1 个答案:

答案 0 :(得分:0)

我明白了。问题是,当我向实体添加合同,服务或位置时,我没有更新id对象以反映这一点。一旦我发现解决方案很简单。在具有组合键的实体(在我的案例中为ContractServiceLocation.java)中,对于构成组合键的属性的setter,我添加了这段代码:

public void setContract(Contract contract) {
    this.contract = contract;
    this.id.setContractId(contract.getId()); //added line
}

所以每次我设置/更改复合属性时,id都会反映出来。

这也不完美(但现在有效),可以通过检查属性id是否为null / default以及是否抛出异常来改进。