我正在使用以下框架:
我有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 JPAR存储库:
@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]
我不明白为什么。映射中是否缺少某些内容,或者我是否必须清除hibernate缓存? 我看到没有新的select-query所以hibernate正在缓存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是放置龙目岛的@Data注释产生我的getter和setter的地方。
通过使用Lomboks @EqualsAndHashCode(exclude = {&#34; b&#34;})删除对hashCode和equals /的依赖关系来解决
答案 0 :(得分:2)
您的测试使用单个会话在单个事务中运行。因此,当您执行aRepository.findOne(a.getId())
时,Hibernate会返回已在其第一级缓存中的A。因为你忘了将B添加到A中的B组,所以这个集合仍然是空的。
您有责任保持对象图的一致性。如果您执行b.setA(a)
,则还应执行a.getBs().add(b)
。最好的方法是将这两个操作封装到A中的方法addB(B b)
中,该方法将B添加到集合中并初始化B.a
。