java - JPA 复合键与 ManyToOne 获取 org.hibernate.PropertyAccessException : could not set a field value by reflection setter of

标签 java hibernate jpa one-to-many many-to-one

我有一个复合键 ContractServiceLocationPK 由三个 id (contractId, locationId, serviceId) 组成在可嵌入类中键入 long。使用此复合键的类 ContractServiceLocation 使用 @MapsId 注释将这些 ID 映射到它们的对象。这是它的样子(删除了 setter/getter 和不相关的属性):

契约(Contract)

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

    public Contract() {
    }

    @Id
    @GeneratedValue
    private long id;
    @OneToMany(mappedBy = "contract", cascade = CascadeType.ALL, fetch= FetchType.EAGER)
    Collection<ContractServiceLocation> contractServiceLocation;
}

ContractServiceLocationPK

@Embeddable
public class ContractServiceLocationPK implements Serializable {

    private long contractId;
    private long locationId;
    private long serviceId;
}

契约(Contract)服务地点

@Entity
@Table(name="Contract_Service_Location")
public class ContractServiceLocation implements Serializable {

    @EmbeddedId
    ContractServiceLocationPK id;

    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("contractId")
    Contract contract;

    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("locationId")
    Location location;

    @ManyToOne(cascade = CascadeType.ALL)
    @MapsId("serviceId")
    Service service;    

    BigDecimal price;
}

当尝试以任何方式(直接或通过契约(Contract))持久化 ContractServiceLocation 类型的对象时,我得到:

Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: could not set a field value by reflection setter of com.test.model.ContractServiceLocationPK.contractId
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1187)
    at com.test.MainTest.main(MainTest.java:139)
Caused by: org.hibernate.PropertyAccessException: could not set a field value by reflection setter of com.test.model.ContractServiceLocationPK.contractId
    at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:134)
    at org.hibernate.mapping.Component$ValueGenerationPlan.execute(Component.java:441)
    at org.hibernate.id.CompositeNestedGeneratedValueGenerator.generate(CompositeNestedGeneratedValueGenerator.java:121)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:117)
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
    ... 1 more
Caused by: java.lang.NullPointerException
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(Unknown Source)
    at sun.reflect.UnsafeLongFieldAccessorImpl.set(Unknown Source)
    at java.lang.reflect.Field.set(Unknown Source)
    at org.hibernate.property.DirectPropertyAccessor$DirectSetter.set(DirectPropertyAccessor.java:122)
    ... 12 more

我的假设是 JPA/Hibernate 需要一个 Contract 对象而不是一个 long 变量,但是如果我将 embeddable 中的变量从 long 更改为它们的类型,那么我得到 The type of the ID mapped by the relationship 'contract ' 与目标实体的主键类不一致。。如果我尝试使用 id 类而不是可嵌入的,那​​么在 Contract 的 OneToMany 映射中使用 mappedby 我得到 In attribute 'contractServiceLocation', the "mapped by"attribute 'contract' has an invalid mapping type for this relationship .。我应该如何制作具有多个 ManyToOne 映射的组合键?

编辑:添加了一个我尝试保留项目的片段:

    Service service = new Service();
    // Set all service properties       
    Contract contract = new Contract();
    // Set all contract properties
    Location location = new Location();
    // Set all location properties
    ContractServiceLocation csl = new ContractServiceLocation();
    csl.setContract(contract);
    csl.setLocation(location);
    csl.setService(service);
    Collection<ContractServiceLocation> cslItems = new ArrayList<>();
    cslItems.add(csl);

    em.getTransaction().begin();
    em.persist(location);
    em.persist(service);
    em.persist(csl);
    em.persist(contract);
    em.getTransaction().commit();

它看起来像这样而不是在某些 DAO 中的原因是因为我在继续开发应用程序的其余部分之前先生成数据库并测试项目。

编辑 2: 我重写了我的模型,现在一切似乎都正常工作,除了在 Eclipse 中我得到一个持续的错误。这是目前的情况:

契约(Contract) - 没有变化(除了删除了 Eager loading)

ContractServiceLocationPK - 现在是一个 ID 类

public class ContractServiceLocationPK implements Serializable {

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)      
    @JoinColumn(name = "contract_id")
    private Contract contract;
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)      
    @JoinColumn(name = "location_id")
    private Location location;
    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)      
    @JoinColumn(name = "service_id")
    private Service service;

    //getters and setters
    //overridden equals() and hashCode()
}

契约(Contract)服务地点

@Entity
@Table(name="Contract_Service_Location")
@IdClass(ContractServiceLocationPK.class)
public class ContractServiceLocation implements Serializable {

    @Id
    Contract contract;

    @Id
    Location location;

    @Id
    Service service;    

    BigDecimal price;
        //getters and setters
        //overridden equals() and hashCode()
}

目前这似乎可以正常工作。它创建一个复合键并与所有复合属性保持多对一的关系。然而,有一点很奇怪。在 Contract eclipse 中,在 ContractServiceLocation 集合的 @OneToMany 注释上标记 mappedBy 并显示错误消息 在属性“contractServiceLocation”中,“mapped by"属性 'contract' 具有此关系的无效映射类型。。我假设这是因为 ContractServiceLocation 中定义的 Contract 属性没有 @ManyToOne 注释,但在复合类。我是否偶然发现了“不符合 JPA 但使用 Hibernate”陷阱或这里发生了什么?

最佳答案

对于您的原始问题(未修改的变体):

您必须在 ContractServiceLocation 类中实例化“ContractServiceLocationPK id”。替换行:

@EmbeddedId ContractServiceLocationPK id;

用这个:

@EmbeddedId ContractServiceLocationPK id = new ContractServiceLocationPK();

那么它应该可以工作了。因为 Hibernate 试图在内部设置属性,但在 NullPointerException 上失败。

关于java - JPA 复合键与 ManyToOne 获取 org.hibernate.PropertyAccessException : could not set a field value by reflection setter of,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23736422/

相关文章:

java - Flyway/springboot - 配置为在生产/测试上运行,但不在开发上运行

java - hibernate.cfg.xml-如何合并它

java - Spring Data JPA 存储库的动态模式选择(模式来自数据库)

java - 动态属性名称搜索

java - 缩小图像按钮中的位图以避免内存不足

java - Spring Boot 桌面独立应用程序中的 Apache Shiro

java - 图标有问题

java - Hibernate 正在自动保存一个全新的实体(完整的调用堆栈)

java - org.apache.struts2.json.JSONException : org. hibernate.LazyInitializationException:未能延迟初始化集合

java - 为什么我的数据没有持久化?