简体   繁体   English

使用ManyToOne获取org.hibernate.PropertyAccessException的JPA Composite键:无法通过反射设置器设置字段值

[英]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( contractIdlocationIdserviceId )组成。 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.

相关问题 org.hibernate.PropertyAccessException:无法使用复合键设置字段值 - org.hibernate.PropertyAccessException: Could not set field value with Composite Key 如何修复org.hibernate.PropertyAccessException:无法通过反射设置器设置字段值 - How to fix org.hibernate.PropertyAccessException: Could not set field value value by reflection setter of org.hibernate.PropertyAccessException:无法通过反射getter获取字段值 - org.hibernate.PropertyAccessException: could not get a field value by reflection getter of Hibernate &amp; Spring - org.hibernate.PropertyAccessException: 无法通过反射设置字段值 [1] 值 - Hibernate & Spring - org.hibernate.PropertyAccessException: Could not set field value [1] value by reflection org.hibernate.PropertyAccessException: 无法通过反射为 String 设置字段值 [STRING] 值 - org.hibernate.PropertyAccessException: Could not set field value [STRING] value by reflection for String 嵌套的异常是org.hibernate.PropertyAccessException:无法设置字段值 - nested exception is org.hibernate.PropertyAccessException: Could not set field value 错误:-org.hibernate.PropertyAccessException:无法通过反射获取器获取字段值 - Error :- org.hibernate.PropertyAccessException: could not get a field value by reflection getter 在连接表和hibernate.PropertyAccessException中映射值:无法通过反射设置器设置字段值 - Mapping Value in Junction Table & hibernate.PropertyAccessException: could not set a field value by reflection setter Hibernate / JPA:无法通过反射设置器设置字段值 - Hibernate/JPA: could not set a field value by reflection setter Java:调用setter和getter时org.hibernate.PropertyAccessException - Java : org.hibernate.PropertyAccessException while calling setter and getter
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM