Java 带有manyTone的JPA复合键获取org.hibernate.PropertyAccessException:无法通过的反射设置器设置字段值
我有一个复合键Java 带有manyTone的JPA复合键获取org.hibernate.PropertyAccessException:无法通过的反射设置器设置字段值,java,hibernate,jpa,one-to-many,many-to-one,Java,Hibernate,Jpa,One To Many,Many To One,我有一个复合键ContractServiceLocationPK,由三个id(contractId,locationId,serviceId)组成,类型为long,位于一个可嵌入类中。使用此复合键的类,ContractServiceLocation,使用@MapsId注释将这些ID映射到它们的对象。下面是它的样子(删除了setter/getter和不相关的属性): 合同 @Entity @Table(name = "Contract") public class Contract impleme
ContractServiceLocationPK
,由三个id(contractId
,locationId
,serviceId
)组成,类型为long,位于一个可嵌入类中。使用此复合键的类,ContractServiceLocation
,使用@MapsId
注释将这些ID映射到它们的对象。下面是它的样子(删除了setter/getter和不相关的属性):
合同
@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;
}
合同服务地点
@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;
}
@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()
}
尝试以任何方式(直接或通过契约)持久化ContractServiceLocation类型的对象时,我得到:
我的假设是JPA/Hibernate需要一个契约对象而不是一个长变量,但是如果我将Embeddeble中的变量从long更改为它们的类型,那么我得到的关系“契约”映射的ID类型与目标实体的主键类不一致。
。如果我尝试使用id类而不是Embeddeble,那么在Contract的OneToMany映射中,我在属性“contractServiceLocation”中得到了“mappedby”,属性“Contract”的“mappedby”对此关系具有无效的映射类型。。我应该怎么做才能使复合键具有多个manytone
映射
编辑:添加了一个片段,我尝试在其中保存项目:
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();
合同服务地点
@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;
}
@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()
}
目前看来,这是正确的。它创建一个复合键,并与所有复合属性保持多对一关系。然而,有一些奇怪的事情。在带有属性“ContractServiceLocation”中错误消息的
ContractServiceLocation
集合的@OneToMany
注释上的Contract eclipse标记mappedBy
中,“mappedBy”属性“Contract”对此关系具有无效的映射类型。。我假设这是因为ContractServiceLocation
中定义的Contract
属性没有@manytone
注释,而是在复合类中定义的。我是不是偶然发现了“不兼容JPA但使用Hibernate”的陷阱,或者这里发生了什么事?您需要将getter和setter也放在@Embeddeble类中,您的hashCode()和equals()方法将放在我在这里发布的类中看不到的类中
为了保存ContractServiceLocation,需要首先保存以下对象,因为您使用它们的ID作为ContractServiceLocation的复合键,对吗?在这里,您要做的是将这些对象创建为新对象,以便它们显然没有id,因为它们没有持久化。因此,您需要首先持久化它们,然后使用持久化对象并将对象设置到ContractServiceLocation中
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类中安装“ContractServiceLocationPK id”。替换行: @嵌入ID ContractServiceLocationPK id 为此: @嵌入ID ContractServiceLocationPK id=新ContractServiceLocationPK()
那么它应该会起作用。因为Hibernate试图在内部设置属性,但在NullPointerException上失败。如果您使用
ContractServiceLocation
的构造函数初始化ContractServiceLocationPK
很高兴我找到了这个问题和答案,那么它也可以工作。这是相当“令人惊讶的”。例如,EclipseLink 2.6.4在相同的上下文中运行良好。谢谢。可怕的情况是,如此重要和有价值的库hibernate忽略了与联接表中附加字段的多对多关系。这是一个核心的、基本的RDBMS设计组件。人们必须创建一个嵌入式id(别忘了实例化它)并经历如此多的诡计才能让它工作,这是不真实的。这是典型的hibernate和对Java如此痴迷的社区,在本例中,它忽略了RDBMS的基础知识……在3天的搜索和阅读之后(并验证这是我的案例)。内部尖叫
Service service = new Service();
// Set all service properties
Contract contract = new Contract();
// Set all contract properties
Location location = new Location();
// Set all location properties