我正在使用以下框架:
- 休眠 4.2.0.Final
- Spring 3.2.2.RELEASE
- Spring Data Jpa 1.1.0.RELEASE
- HSQL 2.2.9
- 测试NG 6.1.1
我有 2 个实体:
实体 A:
@Entity
@Table( name = "A" )
public class A {
@Id
@GeneratedValue( strategy = GenerationType.IDENTITY )
private Long id;
@OneToMany( fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "a" )
private Set<B> b = new HashSet<B>();
//... getter and setter
}
和实体 B:
@Entity
@Table( name = "B" )
public class B {
@Id
@GeneratedValue( strategy = GenerationType.IDENTITY )
private Long id;
@ManyToOne
@JoinColumn( name = "a_id" )
private A a;
//... getter and setter
}
我为他们制作了 Spring Data JPARepositories:
@Repository
public interface ARepository
extends JpaRepository<A, Long> {
}
@Repository
public interface BRepository
extends JpaRepository<B, Long> {
}
然后我写了一个测试来看看映射是否有效:
@TransactionConfiguration( defaultRollback = true )
@ContextConfiguration
public class ARepositoryTest
extends AbstractTransactionalTestNGSpringContextTests {
@Inject
@Setter
private ARepository aRepository;
@Inject
@Setter
private BRepository bRepository;
@Test( groups = { "integration" } )
public void testSaveWithFeed() {
A a = new A();
aRepository.saveAndFlush( a );
B b = new B();
b.setA( a );
bRepository.saveAndFlush( b );
A findOne = aRepository.findOne( a.getId() );
Assert.assertEquals( 1, findOne.getB().size() );
}
}
但测试失败:
Hibernate: insert into A (id) values (default)
Hibernate: insert into B (id, a_id) values (default, ?)
FAILED: testSaveWithA
java.lang.AssertionError: expected [1] but found [0]
我不明白为什么。映射中是否缺少某些内容,或者我是否必须清除休眠缓存?我看到没有新的选择查询,所以休眠正在缓存 A 对象 - 但它不应该更新从 A 到缓存中 Bs 的引用吗?
作为附加信息,这里是我的 persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="local" transaction-type="RESOURCE_LOCAL" >
</persistence-unit>
</persistence>
我的 ARepositoryTest-context.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="my.package"/>
<import resource="classpath:/SpringBeans.xml"/>
</beans>
和我的 SpringBeans.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd">
<context:annotation-config />
<jpa:repositories base-package="my.package.dao" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="local"/>
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect"/>
<property name="database" value="HSQL" />
</bean>
</property>
<property name="jpaPropertyMap">
<map>
<entry key="hibernate.show_sql" value="true" />
</map>
</property>
</bean>
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:file:${user.home}/data;shutdown=true" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
</beans>
编辑:添加版本号和 xml 文件
编辑:对于 JB Nizet 回答如果我添加到 A 类
public void addB( B b ) {
this.b.add( b );
}
并调整测试用例
@Test( groups = { "integration" } )
public void testSaveWithA() {
A a = new A();
aRepository.save( a );
B b = new B();
a.addB( b );
aRepository.saveAndFlush( a );
A findOne = aRepository.findOne( a.getId() );
Assert.assertEquals( findOne.getB().size(), 1 );
}
测试通过但在 hsql 文件中,A 和 B 之间没有链接:
INSERT INTO A VALUES(1)
INSERT INTO B VALUES(1,NULL)
因此它将无法在其他事务中正确选择它。
如果我在 A 中扩展新的 mMethod
public void addB( B b ) {
this.b.add( b );
b.setA( this );
}
刷新或提交时发生异常
java.lang.StackOverflowError
at java.util.HashMap$KeyIterator.<init>(HashMap.java:926)
at java.util.HashMap$KeyIterator.<init>(HashMap.java:926)
at java.util.HashMap.newKeyIterator(HashMap.java:940)
at java.util.HashMap$KeySet.iterator(HashMap.java:974)
at java.util.HashSet.iterator(HashSet.java:170)
at java.util.AbstractSet.hashCode(AbstractSet.java:122)
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:429)
at my.package.A.hashCode(A.java:17)
at my.package.B.hashCode(B.java:13)
at java.util.AbstractSet.hashCode(AbstractSet.java:126)
at org.hibernate.collection.internal.PersistentSet.hashCode(PersistentSet.java:429)
at my.package.A.hashCode(A.java:17)
at my.package.B.hashCode(B.java:13)
...
Linenumbers A.java:17 和 B.java:13 是放置 Lombok 的 @Data 注释的位置,生成我的 getter 和 setter。
通过使用 Lomboks @EqualsAndHashCode( exclude = { "b" } ) 删除对 lombok 的 hashCode 和 equals / 的依赖关系来解决