具有ManyToOne的JPA组合键获取org.hibernate.PropertyAccessException:无法通过反射设置器设置字段值 [英] JPA Composite key with ManyToOne getting org.hibernate.PropertyAccessException: could not set a field value by reflection setter of

查看:701
本文介绍了具有ManyToOne的JPA组合键获取org.hibernate.PropertyAccessException:无法通过反射设置器设置字段值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

合同

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

public Contract(){
}

@Id
@GeneratedValue
私人长ID;
@OneToMany(mappedBy =contract,cascade = CascadeType.ALL,fetch = FetchType.EAGER)
Collection< ContractServiceLocation> contractServiceLocation;
}

ContractServiceLocationPK

  @Embeddable 
public class ContractServiceLocationPK实现Serializable {

private long contractId;
private long locationId;
私人长期serviceId;
}

ContractServiceLocation

 @Entity 
@Table(name =Contract_Service_Location)
public class ContractServiceLocation实现Serializable {

@EmbeddedId
ContractServiceLocationPK id ;

@ManyToOne(cascade = CascadeType.ALL)
@MapsId(contractId)
合约;

@ManyToOne(cascade = CascadeType.ALL)
@MapsId(locationId)
位置位置;

@ManyToOne(cascade = CascadeType.ALL)
@MapsId(serviceId)
服务服务;

BigDecimal价格;
}

当试图以任何方式持续保存一个类型为ContractServiceLocation的对象时(直接或通过合同)我得到:

 线程main中的异常javax.persistence.PersistenceException:org.hibernate.PropertyAccessException:无法设置在org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
。通过com.test.model.ContractServiceLocationPK.contractId
的反射设定部字段值在org.hibernate.jpa。 spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
处org.hibernate.jpa.spi.AbstractEntityManagerImpl org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
。 persist(AbstractEntityManagerImpl.java:1187)
at com.test.MainTest.main(MainTest.java:139)
引起:org.hibernate.PropertyAccessException:无法通过反射设置字段值setter com.test.model.Contract ServiceLocationPK.contractId $在org.hibernate.property.DirectPropertyAccessor $ DirectSetter.set(DirectPropertyAccessor.java:134)
在org.hibernate.mapping.Component $ ValueGenerationPlan.execute(Component.java:441)
b $ b。在在org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:117)
org.hibernate.id.CompositeNestedGeneratedValueGenerator.generate(CompositeNestedGeneratedValueGenerator.java:121)
。在组织。 hibernate.jpa.event.internal.core.JpaPersistEventListener.saveWithGeneratedId(JpaPersistEventListener.java:84)
在org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:206)
。在组织。 hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:149)
在org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
。在org.hibernate.internal。硒(org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:811)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java: 789)
在org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
... 1 more
引起: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变量,但是如果我将变量嵌入long中变为它们的类型,那么我得到由关系'合同'映射的ID不符合主表ry目标实体的关键类。。如果我尝试使用id类而不是可嵌入的,那​​么在Contract的OneToMany映射中 mappedby 我得到在属性'contractServiceLocation'中,mapped by属性'contract '这个关系有一个无效的映射类型。。我应该怎么做一个具有多个 ManyToOne 映射的组合键?



编辑:添加了一个片段,我尝试坚持这些项目:

  Service service = new Service(); 
//设置所有服务属性
Contract contract = new Contract();
//设置所有合约属性
位置位置= new Location();
//设置所有位置属性
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(合约);
em.getTransaction()。commit();

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



编辑2:我重写了我的模型,似乎工作,除了在Eclipse中我得到一个持久性错误。以下是目前的情况:

合约 - 无变化(除去Eager加载)

ContractServiceLocationPK - 现在是一个ID类

  public class ContractServiceLocationPK实现Serializable {

@ManyToOne(cascade = CascadeType。 ALL,fetch = FetchType.EAGER)
@JoinColumn(name =contract_id)
私人合约合约;
@ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
@JoinColumn(name =location_id)
私人位置位置;
@ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
@JoinColumn(name =service_id)
私人服务服务;
$ b $ // getters和setters
//覆盖equals()和hashCode()
}

ContractServiceLocation

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

@Id
合约;

@Id
位置位置;

@Id
服务服务;

BigDecimal价格;
// getters和setters
//覆盖equals()和hashCode()
}

现在看起来可以正常工作。它创建一个组合键并与所有组合属性保持多对一的关系。然而有些奇怪。在合约eclipse中, mappedBy @OneToMany 批注中为 ContractServiceLocation 收集错误消息在属性'contractServiceLocation'中,映射的属性'contract'具有该关系的无效映射类型。我假设这是因为 ContractServiceLocation 中定义的 Contract 属性没有 @ManyToOne 注释,但是它是在复合类中定义的。我偶然发现不兼容的JPA,但使用Hibernate陷阱或这里发生了什么? 解决方案

(未修改变体):

您必须在ContractServiceLocation类中创建ContractServiceLocationPK id。替换行:


@EmbeddedId
ContractServiceLocationPK id;

与此:


@EmbeddedId
ContractServiceLocationPK id = new ContractServiceLocationPK();


然后它应该可以工作。因为Hibernate试图在内部设置属性,但在NullPointerException中失败。


I have a composite key ContractServiceLocationPK made out of three id's (contractId, locationId, serviceId) of type long in an embeddable class. The class which uses this composite key, ContractServiceLocation, maps these ids, using @MapsId annotation, to their objects. Here's how it looks like (removed setters/getters and irrelevant properties):

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;
}

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:

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.. 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.. What should I do to make a composite key with multiple ManyToOne mappings?

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.

EDIT 2: I've rewrote my models and now everything seems to work except in Eclipse I get a persistent error. Here's how the things currently look:

Contract - No change (Except removed the Eager loading)

ContractServiceLocationPK - Is now an ID class

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

@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.. 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. Did I stumble upon "non-compliant JPA but working with Hibernate" trap or what's going on here?

解决方案

For your original question (not modified variant):

You have to instatiate "ContractServiceLocationPK id" in your ContractServiceLocation class. Replace line:

@EmbeddedId ContractServiceLocationPK id;

with this:

@EmbeddedId ContractServiceLocationPK id = new ContractServiceLocationPK();

Then it should works. Because Hibernate is trying to set properties inside, but fail on NullPointerException.

这篇关于具有ManyToOne的JPA组合键获取org.hibernate.PropertyAccessException:无法通过反射设置器设置字段值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆