[英]PropertyAccessException when using Criteria API to query an entity with self-reference
[英]PropertyAccessException when saving entity with @Embeddable
我正在跟蹤這張地圖,其中包含多列關聯以及額外的列教程,但並不太成功。
所以我有以下實體...
@Data
@Entity
@Table(name = "PEOPLE")
public class People implements Serializable {
@Id
@SequenceGenerator(name = "people", sequenceName = "people_id_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "people")
private long peopleId;
private String peopleName;
@ToString.Exclude
@EqualsAndHashCode.Exclude
@OneToMany(
mappedBy = "people",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PeopleStats> peopleStats;
public void addStats(Stats stats) {
if (this.peopleStats == null) {
this.peopleStats = new ArrayList<>();
}
PoepleStats pStats = PoepleStats.builder().people(this).stats(stats).build();
this.peopleStats.add(pStats);
}
}
@Data
@Entity
@Table(name = "STATS")
public class Stats implements Serializable {
@Id
@SequenceGenerator(name = "stats", sequenceName = "stats_id_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "stats")
private long statsId;
private String statsName;
private String statsDescription;
}
@Data
@Entity
@Table(name = "PEOPLE_STATS")
public class PeopleStats implements Serializable {
@EmbeddedId
private PeopleStatsId peopleStatsId;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("peopleId")
private People people;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("statsId")
private Stats stats;
private long value;
}
@Data
@Embeddable
@EqualsAndHashCode
public class PeopleStatsId implements Serializable {
// Putting @Column(name = "people_id") or not doesn't seem to have any effect
private long peopleId;
// Same goes for this
private long statsId;
}
然后進行以下單元測試。
@RunWith(SpringRunner.class)
@DataJpaTest
public class PeopleRepositoryTest {
@Autowired
private TestEntityManager entityManager;
@Test
public void testSavePeople() {
// People object created
people.addStats(Stats.builder().statsId(new Long(1)).statsName("a").statsDescription("b").build());
this.entityManager.persistAndFlush(people);
}
}
休眠生成的表是這樣的:
Hibernate: create table people_stats (value bigint not null, people_people_id bigint not null, stats_stats_id bigint not null, primary key (people_people_id, stats_stats_id))
這是stacktrace。
javax.persistence.PersistenceException:org.hibernate.PropertyAccessException:無法通過反射設置字段值1的值:[class com.sample.shared.entity.PeopleStatsId.peopleId] com.sample.shared.entity.PeopleStatsId.peopleId的設置者org.hibernate.internal.ExceptionConverterImpl.convert(Exception。更多
我遇到了類似的問題 ,但沒有解決方案。 在嘗試第一個解決方案后,即為@EmbeddedId
創建一個new PeopleStatsId
對象,它引發了相同的錯誤。
有人可以引導我前進嗎? 謝謝。
更新1:我已經在github上上傳了POC。
更新2 :
public void addStats(Stats stats) {
if (this.peopleStats == null) {
this.peopleStats = new ArrayList<>();
}
PeopleStats pStats = PeopleStats.builder().peopleStatsId(new PeopleStatsId()).people(this).stats(stats).build();
this.peopleStats.add(pStats);
}
現在,它拋出分離的實體錯誤。
引起原因:org.hibernate.PersistentObjectException:傳遞給持久對象的分離實體:org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124)上的com.sample.Stats org.hibernate.internal.SessionImpl.firePersist( SessionImpl.java:807)...還有68
更新3 :
我已經將CascadeType.ALL
更改為MERGE
,看來可以解決問題,但是我不確定為什么。 我什至刪除了更新2中有關.peopleStatsId(new PeopleStatsId())
,它也可以正常工作。 現在我更加困惑。
在人類中:
@OneToMany(
mappedBy = "people",
cascade = CascadeType.MERGE,
orphanRemoval = true
)
private List<PeopleStats> peopleStats;
public void addStats(Stats stats) {
if (this.peopleStats == null) {
this.peopleStats = new ArrayList<>();
}
PeopleStats pStats = PeopleStats.builder().people(this).stats(stats).build();
this.peopleStats.add(pStats);
}
您需要在PeopleStats類中實例化peopleStatsId。 所以換行:
@EmbeddedId
private PeopleStatsId peopleStatsId;
對此:
@EmbeddedId
private PeopleStatsId peopleStatsId = new PeopleStatsId();
Hibernate嘗試設置PeopleStatsId的字段,但該實例等於null,因此拋出NullPointerException。
因此,在@K.Nicholas
和研究的幫助下,我認為我已經設法解決了問題並從中學到了新東西。
@K.Nicholas
關於設置“人員”和“統計”的字段是正確的,但最初對我來說還不太清楚。 無論如何,后來我想到了。
基本上,除“ People
課程外,所有其他課程幾乎保持相同。
@Data
@Entity
@Builder
@Table(name = "PEOPLE")
public class People implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@SequenceGenerator(name = "people", sequenceName = "people_id_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.AUTO, generator = "people")
private long peopleId;
private String peopleName;
@ToString.Exclude
@EqualsAndHashCode.Exclude
@OneToMany(
mappedBy = "people",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PeopleStats> peopleStats;
// Maintain the state of objects association
public void addStats(Stats stats) {
if (this.peopleStats == null) {
this.peopleStats = new ArrayList<>();
}
// Important to ensure that a new instance of PeopleStatsId is being passed into the field
// otherwise, PropertyAccessException will be encountered
PeopleStats pStats = PeopleStats.builder()
.people(this)
.stats(stats)
.peopleStatsId(new PeopleStatsId(this.getPeopleId(), stats.getStatsId()))
.build();
this.peopleStats.add(pStats);
}
}
請注意addStats
方法中的注釋,在該注釋中,我需要傳遞一個新的PeopleStatsId
對象實例以初始化PeopleStatsId
對象,該對象首先應該已經完成,但實際上並非必須如此。 學習到教訓了。
我還提到我以前曾遇到過獨立實體的問題。 這是因為我在不需要時會嘗試在“統計信息ID”字段中進行設置。
根據《 休眠指南》 ,
超脫
實體具有關聯的標識符,但不再與持久性上下文關聯(通常是因為持久性上下文已關閉或實例已從上下文中退出)
在我的帖子中,我試圖將“統計數據”設置為“人”,然后堅持下去。
@Test
public void testSavePeople() {
// People object created
people.addStats(Stats.builder().statsId(new Long(1)).statsName("a").statsDescription("b").build());
this.entityManager.persistAndFlush(people);
}
.statsId(new Long(1))
是問題所在,因為由於存在ID,它被視為獨立實體。 CascadeType.MERGE
在這種情況下可以工作是因為我認為由於saveOrUpdate功能? 無論如何,如果不設置statsId, CascadeType.ALL
就可以正常工作。
單元測試的樣本(工作中):
@Test
public void testSavePeopleWithOneStats() {
// Creates People entity
People people = this.generatePeopleWithoutId();
// Retrieve existing stats from StatsRepository
Stats stats = this.statsRepository.findById(new Long(1)).get();
// Add Stats to People
people.addStats(stats);
// Persist and retrieve
People p = this.entityManager.persistFlushFind(people);
assertThat(p.getPeopleStats().size()).isEqualTo(1);
}
我有一個data-h2.sql
腳本,該腳本在單元測試開始時就加載了Stats數據,這就是為什么我可以從statsRepository
檢索它的statsRepository
。
希望這對接下來的人有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.