[英]JPA Composite key with ManyToOne getting org.hibernate.PropertyAccessException: could not set a field value by reflection setter of
I have a composite key ContractServiceLocationPK
made out of three id's ( contractId
, locationId
, serviceId
) of type long in an embeddable class. 我有一个复合键
ContractServiceLocationPK
由一个嵌入类中long类型的三个id( contractId
, locationId
, serviceId
)组成。 The class which uses this composite key, ContractServiceLocation
, maps these ids, using @MapsId
annotation, to their objects. 使用此组合键
ContractServiceLocation
的类使用@MapsId
注释将这些ID映射到它们的对象。 Here's how it looks like (removed setters/getters and irrelevant properties): 这是它的样子(删除了setter / getters和不相关的属性):
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 ContractServiceLocationPK
@Embeddable
public class ContractServiceLocationPK implements Serializable {
private long contractId;
private long locationId;
private long serviceId;
}
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;
}
When attempting to persist an object of type ContractServiceLocation in any way(directly or throught contract) I get: 当试图以任何方式(直接或通过合同)持久化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
My assumption is that JPA/Hibernate expects a Contract object instead of a long variable, but if I change the variables in embeddable from long to their type then I get The type of the ID mapped by the relationship 'contract' does not agree with the primary key class of the target entity.
我的假设是JPA / Hibernate期望一个Contract对象而不是一个long变量,但如果我将embeddable中的变量从long更改为他们的类型,那么我得到
The type of the ID mapped by the relationship 'contract' does not agree with the primary key class of the target entity.
. 。 If I try using id class instead of embeddable then
mappedby
in Contract's OneToMany mapping I get In attribute 'contractServiceLocation', the "mapped by" attribute 'contract' has an invalid mapping type for this relationship.
如果我尝试使用id类而不是embeddable然后在Contract的OneToMany映射中使用
mappedby
,我得到In attribute 'contractServiceLocation', the "mapped by" attribute 'contract' has an invalid mapping type for this relationship.
. 。 What should I do to make a composite key with multiple
ManyToOne
mappings? 如何制作具有多个
ManyToOne
映射的复合键?
EDIT: Added a snippet where I try to persist the items: 编辑:添加了一个片段,我尝试持久化项目:
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();
The reason it looks like this instead of being in some DAO is because I'm generating the database and testing the items first before I get on with developing the rest of the app. 它看起来像这样而不是在某些DAO中的原因是因为我在开发应用程序的其余部分之前首先生成数据库并测试项目。
EDIT 2: I've rewrote my models and now everything seems to work except in Eclipse I get a persistent error. 编辑2:我已经重写了我的模型,现在一切似乎都工作,除了在Eclipse中我得到一个持久的错误。 Here's how the things currently look:
以下是目前的情况:
Contract - No change (Except removed the Eager loading) 合同 - 没有变化(除非删除了预先加载)
ContractServiceLocationPK - Is now an ID class 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()
}
ContractServiceLocation ContractServiceLocation
@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()
}
This appears to work correctly for now. 这似乎现在正常工作。 It creates a composite key and maintains a many-to-one relationship with all the composite properties.
它创建一个复合键,并与所有复合属性保持多对一关系。 However there is something weird.
然而,有一些奇怪的东西。 In Contract eclipse marks
mappedBy
on the @OneToMany
annotation for the ContractServiceLocation
collection with the error message In attribute 'contractServiceLocation', the "mapped by" attribute 'contract' has an invalid mapping type for this relationship.
在合同蚀痕
mappedBy
上@OneToMany
注释为ContractServiceLocation
收集并显示错误消息In attribute 'contractServiceLocation', the "mapped by" attribute 'contract' has an invalid mapping type for this relationship.
. 。 I'm assuming that this is because the
Contract
property defined in ContractServiceLocation
doesn't have a @ManyToOne
annotation, but that is defined in the composite class. 我假定这是因为
Contract
中定义的属性ContractServiceLocation
没有一个@ManyToOne
注释,但在复合类中定义。 Did I stumble upon "non-compliant JPA but working with Hibernate" trap or what's going on here? 我是否偶然发现了“不合规的JPA但使用Hibernate”陷阱或者这里发生了什么?
For your original question (not modified variant): 对于您的原始问题(未修改的变体):
You have to instatiate "ContractServiceLocationPK id" in your ContractServiceLocation class. 您必须在ContractServiceLocation类中实例化“ContractServiceLocationPK id”。 Replace line:
替换线:
@EmbeddedId ContractServiceLocationPK id;
@EmbeddedId ContractServiceLocationPK id;
with this: 有了这个:
@EmbeddedId ContractServiceLocationPK id = new ContractServiceLocationPK();
@EmbeddedId ContractServiceLocationPK id = new ContractServiceLocationPK();
Then it should works. 然后它应该工作。 Because Hibernate is trying to set properties inside, but fail on NullPointerException.
因为Hibernate试图在里面设置属性,但在NullPointerException上失败。
You need to put the getters and setters in your @Embeddable class as well, your hashCode() and equals() methods will go in to that class which I couldn't see in your class posted here. 你需要将getter和setter放在你的@Embeddable类中,你的hashCode()和equals()方法将进入你在这里发布的类中看不到的那个类。
In order to save the ContractServiceLocation, following objects needs to be saved first because you are using their ids as composite key for the ContractServiceLocation, right? 为了保存ContractServiceLocation,需要首先保存以下对象,因为您使用它们的ID作为ContractServiceLocation的复合键,对吧? Here what you are doing is you are creating these as new objects so obviously they won't have their id, because they are not persisted.
在这里你正在做的是你正在创建这些作为新对象,所以显然他们不会有他们的id,因为它们不会被持久化。 so you need to persist them first and use the persisted objects and set objects into the ContractServiceLocation.
所以你需要先保留它们并使用持久化对象并将对象设置到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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.