在Sping Boot 3.1(使用Spring Data JPA Starter)中,将实体与具有Composite键的子实体沿着保存失败。我有三个实体名为Invoice
,Product
和InvoiceItem
。InvoiceItem没有自己的唯一键,而是使用invoice_id
,product_id
的复合键。现在我在应用程序中使用EmbeddedId
技术对此进行建模。但是当我保存我的第一张发票时,我得到以下错误
Could not set value of type [java.lang.Long] : `info.fareez.goldin.entities.embeddables.InvoiceItemId.invoiceId` (setter)
我已经检查了所有字段,并与JPA规范和示例进行了比较。我还是无法解决这个问题。
注意:我也尝试了@IdClass技术,它在IdClass和Entity中有重复的字段名称,所以我想用EmbeddedId解决它
这里是代码,
发票:
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Invoice {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "customer_id", nullable = true)
private Customer customer;
@OneToMany(mappedBy = "invoice", cascade = CascadeType.PERSIST)
private List<InvoiceItem> invoiceItems;
private Date timestamp;
private double price;
}
产品
@Builder
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String code;
private String name;
private double purity;
private double weight;
private int stock;
@OneToMany(mappedBy = "product")
private List<InventoryTransaction> inventoryTransactions;
}
InvoiceItem
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Embeddable
public class InvoiceItemId {
private Long invoiceId;
private Long productId;
}
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class InvoiceItem {
@EmbeddedId
private InvoiceItemId invoiceItemId;
@MapsId("invoiceId")
@ManyToOne
private Invoice invoice;
@MapsId("productId")
@OneToOne
private Product product;
private Double price;
}
当我试图用下面的代码保存一个新的发票时
List<InvoiceItem> invoiceItems = new ArrayList<>();
var invoice = Invoice.builder()
.customer(customer)
.timestamp(new Date()).build();
for (var itemDto : invoiceRequest.getInvoiceItems()) {
// prepare invoice items here
invoiceItems.add(
InvoiceItem.builder()
.invoice(invoice)
.product(product.toProduct())
// other fields
.build())
}
invoice.setInvoiceItems(invoiceItems);
invoice.setPrice(totalPrice);
invoiceRepository.save(invoice);
我得到以下错误
Caused by: org.hibernate.PropertyAccessException: Could not set value of type [java.lang.Long] : `info.fareez.goldin.entities.embeddables.InvoiceItemId.invoiceId` (setter)
at org.hibernate.property.access.spi.SetterFieldImpl.set(SetterFieldImpl.java:81) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.mapping.Component$ValueGenerationPlan.execute(Component.java:538) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.id.CompositeNestedGeneratedValueGenerator.generate(CompositeNestedGeneratedValueGenerator.java:113) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:114) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:184) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:129) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:118) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:779) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:727) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:301) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:291) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:513) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:434) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:220) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:547) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:477) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:437) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:220) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:153) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:474) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:192) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:122) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:184) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:129) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:53) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:737) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:721) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:311) ~[spring-orm-6.0.7.jar:6.0.7]
at jdk.proxy3/jdk.proxy3.$Proxy122.persist(Unknown Source) ~[na:na]
at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:613) ~[spring-data-jpa-3.0.4.jar:3.0.4]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:288) ~[spring-data-commons-3.0.4.jar:3.0.4]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:136) ~[spring-data-commons-3.0.4.jar:3.0.4]
at org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:120) ~[spring-data-commons-3.0.4.jar:3.0.4]
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:516) ~[spring-data-commons-3.0.4.jar:3.0.4]
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285) ~[spring-data-commons-3.0.4.jar:3.0.4]
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:628) ~[spring-data-commons-3.0.4.jar:3.0.4]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.0.7.jar:6.0.7]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:168) ~[spring-data-commons-3.0.4.jar:3.0.4]
at org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:143) ~[spring-data-commons-3.0.4.jar:3.0.4]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.0.7.jar:6.0.7]
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:77) ~[spring-data-commons-3.0.4.jar:3.0.4]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.0.7.jar:6.0.7]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) ~[spring-tx-6.0.7.jar:6.0.7]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:391) ~[spring-tx-6.0.7.jar:6.0.7]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) ~[spring-tx-6.0.7.jar:6.0.7]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184) ~[spring-aop-6.0.7.jar:6.0.7]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137) ~[spring-tx-6.0.7.jar:6.0.7]
... 35 common frames omitted
Caused by: java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "o" is null
1条答案
按热度按时间k3bvogb11#
我发现下面的方法奏效了。
遗憾的是,我必须先持久化
Invoice
,然后分别持久化InvoiceItems
,以便能够访问invoiceId
。lombok Builder也没有正确填充@EmbeddedId
。我还必须将
invoiceItems
设置为CascadeType.ALL