保持多对多关系时出现 PropertyAccessException

Posted

技术标签:

【中文标题】保持多对多关系时出现 PropertyAccessException【英文标题】:PropertyAccessException while persisting Many to Many relationship 【发布时间】:2014-12-23 18:02:43 【问题描述】:

我在尝试保持多对多关系时遇到了以下异常。任何线索将不胜感激。我正在使用hibernate的@ManyToMany注解,如下所示。

如果我从建筑实体中移除房屋然后坚持它就可以了。只有当我在调用persist之前说construction.setHouses(houses)时才会出现问题。我有 3 张桌子:Construction、House 和 Construction_houses。 Construction_houses 使用主键存储建筑和房屋之间的映射。

@ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name="construction_houses",
            joinColumns=@JoinColumn(name="construction_id", referencedColumnName = "id"),
            inverseJoinColumns=@JoinColumn(name="house_id", referencedColumnName = "id"))
private List<House> houses = new ArrayList<>();   

例外:

org.hibernate.PropertyAccessException: could not get a field value by reflection getter of com.construction.domain.House.id
javax.persistence.PersistenceException: org.hibernate.PropertyAccessException: could not get a field value by reflection getter of com.construction.domain.House.id
    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 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:291)
    at com.sun.proxy.$Proxy46.persist(Unknown Source)
    at com.construction.domain.BaseEntity.persist(BaseEntity.java:44)
    at com.construction.service.QuizEngineService.generateQuiz(QuizEngineService.java:83)
    at com.construction.service.QuizEngineService$$FastClassBySpringCGLIB$$e2bbd45a.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:267)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
    at com.construction.service.QuizEngineService$$EnhancerBySpringCGLIB$$4b29f50c.generateQuiz(<generated>)
    at com.construction.service.QuizEngineServiceTest.testQuizEngineServiceMustNotBeNull(QuizEngineServiceTest.java:27)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:217)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:69)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:48)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:105)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:355)
    at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:744)
Caused by: org.hibernate.PropertyAccessException: could not get a field value by reflection getter of com.construction.domain.House.id
    at org.hibernate.property.DirectPropertyAccessor$DirectGetter.get(DirectPropertyAccessor.java:60)
    at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:346)
    at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:4746)
    at org.hibernate.persister.entity.AbstractEntityPersister.isTransient(AbstractEntityPersister.java:4465)
    at org.hibernate.engine.internal.ForeignKeys.isTransient(ForeignKeys.java:243)
    at org.hibernate.event.internal.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:511)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:116)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:801)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:794)
    at org.hibernate.jpa.event.internal.core.JpaPersistEventListener$1.cascade(JpaPersistEventListener.java:97)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:379)
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:319)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:296)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:460)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:294)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:137)
    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)
    ... 67 more
Caused by: java.lang.IllegalArgumentException: Can not set java.lang.Long field com.construction.domain.House.id to [Ljava.lang.Object;
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
    at java.lang.reflect.Field.get(Field.java:387)
    at org.hibernate.property.DirectPropertyAccessor$DirectGetter.get(DirectPropertyAccessor.java:57)
    ... 96 more

House.java

@Entity
@Table(name = "houses")
public class House 

    @Id
    @SequenceGenerator(name = "house_sequence", sequenceName = "house_sequence", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "house_sequence")
    private Long id;

    @Column(name = "description")
    private String description;

    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public String getDescription() 
        return description;
    

    public void setDescription(String description) 
        this.description = description;
    

Construction.java

@Entity
@Table(name = "constructions")
public class Construction 

    @Id
    @SequenceGenerator(name = "construction_sequence", sequenceName = "construction_sequence", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "construction_sequence")
    private Long id;

    @Column(name = "is_completed")
    @Type(type = "yes_no")
    private boolean isCompleted;

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name="construction_houses",
            joinColumns=@JoinColumn(name="construction_id", referencedColumnName = "id"),
            inverseJoinColumns=@JoinColumn(name="house_id", referencedColumnName = "id"))
    private List<House> houses = new ArrayList<>();

    public Long getId() 
        return id;
    

    public void setId(Long id) 
        this.id = id;
    

    public boolean isCompleted() 
        return isCompleted;
    

    public void setCompleted(boolean isCompleted) 
        this.isCompleted = isCompleted;
    

    public List<House> getHouses() 
        return houses;
    

    public void setHouses(List<House> houses) 
        this.houses = houses;
    

【问题讨论】:

您需要发布 House 的代码。 @AlanHay 我已经粘贴了 House.java 类。 @AlanHay 构造类的代码也可用。谢谢。 【参考方案1】:

堆栈跟踪状态:

无法将 java.lang.Long 字段 com.construction.domain.House.id 设置为 [Ljava.lang.Object;

不幸的是,该消息不仅提供给 setter,还提供给 getter。

因此该消息告诉您它尝试读取字段House.id 不是针对House 类型的对象,而是针对Object[] 类型的对象。

您的 houses 似乎不是 House 对象的列表,而是数组 - 或者它至少包含一个这样的数组。

如果您在坚持构建之前致电System.out.println(construction.getHouses());,您会发现类似:...[Ljava.lang.Object;@...

【讨论】:

我不确定你的意思。房屋是一个 ArrayList。它不包含类中所示的任何其他数组。 好的,我找到了问题所在,但不知道如何解决。问题是我分配给建筑对象的房屋已经存在于数据库中。我在坚持建筑对象之前先建造房屋。然后我从数据库中检索房屋并将其分配给构造对象并在构造时调用持久化。这似乎是问题所在。它似乎不喜欢那样。如何将建筑对象与现有房屋保持一致? 您能否在检索房屋的位置添加代码并将其添加到列表中? 正如 Tobias 所指出的,房屋实际上是以数组而不是列表的形式出现的。修复代码后,它现在可以工作了。非常感谢你们。

以上是关于保持多对多关系时出现 PropertyAccessException的主要内容,如果未能解决你的问题,请参考以下文章

自跟踪实体 SaveChanges() 在多对多关系中添加实体时出现异常

向核心数据添加记录时出现 NSSet 错误(多对多关系)

Json序列化,有多对一和多对多关系时出现的问题

实体框架多对多关系错误

打印多对多实体时出现异常

如何在 PostgreSQL 中实现多对多关系?