【发布时间】:2013-11-22 15:21:39
【问题描述】:
为了最初用数据填充数据库,我创建了实体实例并编写了一个将它们保存在数据库中的服务类。
以非常简化的方式,我的模型由三个类 A、B 和 C 组成。类 A 和 B 的实例都引用(相同的)C 实例(用@ManyToOne 注释):
a1 -> c1
a2 -> c2
a3 -> c1
b1 -> c1
b2 -> c2
对于 A 和 B,我使用 JpaRepositories 来保持持久性。
然后我尝试保存我以编程方式创建的实例:
@Transactional
public void save(A a1, A a2, A a3, B b1, B b2) {
aRepo.save(a1);
aRepo.save(a2);
aRepo.save(a3);
bRepo.save(b1);
bRepo.save(b2);
}
我在第三行得到一个异常(“分离的实体传递给持久化:C”),因为实例 c1 已经保存在第一行。
我怎样才能避免这种情况?我认为在我的服务中使用@Transactional 标记我的保存方法就足够了,但显然不是。
我当然可以写
aRepo.save(Arrays.asList(a1, a2, a3));
bRepo.save(Arrays.asList(b1, b2));
但这只会改变我的问题,因为当引用已经保存的 c1 的 b1 应该被保存时,异常发生在第二行。
如何保存我在一种方法中创建的数据结构而不会出现异常?
剩下的代码如下:
@Entity
public class A {
@Id
@GeneratedValue
@Access(AccessType.FIELD)
private Long id;
@ManyToOne(cascade = CascadeType.ALL)
@Access(AccessType.FIELD)
private C c;
public A(C c) {
this.c = c;
}
public C getC() {
return c;
}
}
B类看起来一模一样,C类只包含ID参数。
实例是在测试用例中创建的:
public class DBTest extends AbstractH2TestCase {
@Test
public void testDataStorage() {
final AbstractApplicationContext context = new AnnotationConfigApplicationContext(DBTest.class);
try {
final PersistService persistService = context.getBean(PersistService.class);
C c1 = new C();
C c2 = new C();
A a1 = new A(c1);
A a2 = new A(c2);
A a3 = new A(c1);
B b1 = new B(c1);
B b2 = new B(c2);
persistService.save(b1, b2, a1, a2, a3);
} finally {
context.close();
}
}
}
我在网上某处找到的测试的超类并对其进行了一些修改:
@Configuration
@ComponentScan(basePackageClasses = A.class)
@EnableJpaRepositories
public class AbstractH2TestCase {
public AbstractH2TestCase() {
super();
}
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType(H2).build();
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource,
JpaVendorAdapter jpaVendorAdapter) {
final LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource);
lef.setJpaVendorAdapter(jpaVendorAdapter);
final String thisPackageAndSubpackages = this.getClass().getPackage().getName();
lef.setPackagesToScan(thisPackageAndSubpackages);
return lef;
}
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
final HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(false);
hibernateJpaVendorAdapter.setGenerateDdl(true);
hibernateJpaVendorAdapter.setDatabase(Database.H2);
return hibernateJpaVendorAdapter;
}
@Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager();
}
}
如果您想要代码的运行版本 - 我在这里检查了它:
https://github.com/BernhardBln/stackexchange
这是一个 Maven 项目。
【问题讨论】:
-
能否展示初始化 a1-3 和 c1、c2 实例的代码?
-
我添加了它,还有一个指向 github 的链接,我在其中放置了一个运行示例
标签: java hibernate spring-data-jpa