如何选择与Spring Data JDBC处于一对一关系的引用实体?
当我尝试在this blog上跟踪代码时
class PurchaseOrder {
@Id
private Long id;
private String shippingAddress;
private Set<OrderItem> items;
}
class OrderItem {
@Id
private Long id;
private int quantity;
private String product;
}
@Test
void test() {
PurchaseOrder purchaseOrder = PurchaseOrder.of("Tokyo");
purchaseOrder.addItem(4, "Captain Future Comet Lego set");
purchaseOrder.addItem(2, "Cute blue angler fish plush toy");
orderRepository.save(purchaseOrder);
Iterable<PurchaseOrder> result = orderRepository.findAll(); //throw MappingException !!
result.forEach(System.out::println);
}
这在下面引发异常:
org.springframework.data.mapping.MappingException: Could not read property @org.springframework.data.annotation.Id()private final java.lang.Long com.example.demo.OrderItem.id from result set!
at org.springframework.data.jdbc.core.EntityRowMapper.readFrom(EntityRowMapper.java:130)
at org.springframework.data.jdbc.core.EntityRowMapper.readEntityFrom(EntityRowMapper.java:143)
at org.springframework.data.jdbc.core.EntityRowMapper.readFrom(EntityRowMapper.java:124)
at org.springframework.data.jdbc.core.EntityRowMapper.lambda$createInstance$0(EntityRowMapper.java:167)
......
Caused by: org.h2.jdbc.JdbcSQLException: Column "items_id" not found [42122-197]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
......
看起来,当从ResultSet中检索值时,spring数据jdbc将父实体的名称添加为子实体列的前缀。但是我无法在文档上使用此映射规则...
有什么方法可以自定义此映射规则?
DDL:
create table purchase_order (
id bigint primary key auto_increment,
shipping_address varchar NOT NULL
);
create table order_item (
id bigint primary key auto_increment,
purchase_order bigint NOT NULL,
quantity int NOT NULL,
product varchar NOT NULL
);
[已更新]
spring-data-jdbc的版本是1.0.4.RELEASE。
SQL语句在这里:
2019-01-29 23:49:16.932 DEBUG 80409 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing prepared SQL statement [SELECT purchase_order.id AS id, purchase_order.shipping_address AS shipping_address FROM purchase_order]
完整的堆栈跟踪为
org.springframework.data.mapping.MappingException: Could not read property @org.springframework.data.annotation.Id()private java.lang.Long com.example.demo.OrderItem.id from result set!
at org.springframework.data.jdbc.core.EntityRowMapper.readFrom(EntityRowMapper.java:130)
at org.springframework.data.jdbc.core.EntityRowMapper.readEntityFrom(EntityRowMapper.java:143)
at org.springframework.data.jdbc.core.EntityRowMapper.readFrom(EntityRowMapper.java:124)
at org.springframework.data.jdbc.core.EntityRowMapper.lambda$createInstance$0(EntityRowMapper.java:167)
at org.springframework.data.relational.core.conversion.BasicRelationalConverter$ConvertingParameterValueProvider.getParameterValue(BasicRelationalConverter.java:251)
at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:75)
at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:84)
at org.springframework.data.relational.core.conversion.BasicRelationalConverter.createInstance(BasicRelationalConverter.java:141)
at org.springframework.data.jdbc.core.EntityRowMapper.createInstance(EntityRowMapper.java:160)
at org.springframework.data.jdbc.core.EntityRowMapper.mapRow(EntityRowMapper.java:71)
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:94)
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:61)
at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:679)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:669)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:694)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:748)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:215)
at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.query(NamedParameterJdbcTemplate.java:227)
at org.springframework.data.jdbc.core.DefaultDataAccessStrategy.findAll(DefaultDataAccessStrategy.java:217)
at org.springframework.data.jdbc.core.JdbcAggregateTemplate.findAll(JdbcAggregateTemplate.java:158)
at org.springframework.data.jdbc.repository.support.SimpleJdbcRepository.findAll(SimpleJdbcRepository.java:84)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359)
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy68.findAll(Unknown Source)
at com.example.demo.OrderRepositoryTest.test(OrderRepositoryTest.java:61)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:532)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:171)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:167)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:114)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:59)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:108)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$4(NodeTestTask.java:112)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:98)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:74)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:220)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:188)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:202)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:181)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.h2.jdbc.JdbcSQLException: Column "items_id" not found [42122-197]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.jdbc.JdbcResultSet.getColumnIndex(JdbcResultSet.java:3174)
at org.h2.jdbc.JdbcResultSet.get(JdbcResultSet.java:3247)
at org.h2.jdbc.JdbcResultSet.getObject(JdbcResultSet.java:529)
at org.springframework.data.jdbc.core.EntityRowMapper.readFrom(EntityRowMapper.java:127)
... 86 more
答案 0 :(得分:0)
以下是从官方文档复制过来的。
总结一下:Spring Data JDBC不支持多对一或多对多关系。为了对它们建模,请使用ID。这鼓励域模型的干净模块化。它还消除了人们必须解决并学习推理出是否可能进行此类映射的一整套问题。
class PurchaseOrder {
@Id
private Long id;
private String shippingAddress;
private Set<OrderItem> items;
private OrderItemRef createOrderItem(OrderItem orderItem ) {
OrderItemRef orderItemRef = new OrderItemRef ();
orderItemRef.orderItem = orderItemRef.id;
return orderItemRef ;
}
}
@Table("Purchase_OrderItem ")
class OrderItemRef {
Long orderItem;
}
class OrderItem {
@Id
private Long id;
private int quantity;
private String product;
}