我正在尝试使用JPA映射旧数据库,因此无法更改数据库结构。我有一个实体TableA和一个oneToMany集合tableBs,其中外键在TableB上。此集合中的对象与TableC具有ManyToOne关系。 TableB与TableD也具有oneToOne关系,外键也位于tableB上。 TableD与TableE(具有外键的tableD)具有ManyToOne关系,最后TableE与tableC(具有外键的tableE)具有oneToOne。
当我在表A上调用保存时,我希望它级联对收集表B的所有更改,因此我将级联保存操作。这似乎工作正常,但是当我向集合中添加一个新的TableB实体时,我在tableB实体上设置了一个tableC对象,但是保存后成为代理,但是我需要对其进行初始化。我在下面模拟了一个例子。
数据库表...
CREATE TABLE TABLEA (tableAPk VARCHAR2(10) PRIMARY KEY);
CREATE TABLE TABLEC (ID NUMBER PRIMARY KEY);
CREATE TABLE TABLEE (ID NUMBER PRIMARY KEY, tableEProperty NUMBER,
CONSTRAINT FK_TABLEC2 FOREIGN KEY (tableEProperty) REFERENCES TABLEC(ID));
CREATE TABLE TABLED (ID NUMBER PRIMARY KEY, tableDProperty NUMBER,
CONSTRAINT FK_TABLEE FOREIGN KEY (tableDProperty) REFERENCES TABLEE(ID));
CREATE TABLE TABLEB (ID NUMBER PRIMARY KEY, tableBProperty VARCHAR2(10), tableBProperty2 NUMBER, tableBProperty3 NUMBER,
CONSTRAINT FK_TABLEA FOREIGN KEY (tableBProperty) REFERENCES TABLEA (tableAPk),
CONSTRAINT FK_TABLEC FOREIGN KEY (tableBProperty2) REFERENCES TABLEC (ID),
CONSTRAINT FK_TABLED FOREIGN KEY (tableBProperty3) REFERENCES TABLED (ID));
CREATE SEQUENCE TABLEA_SEQ START WITH 1;
CREATE SEQUENCE TABLEB_SEQ START WITH 1;
CREATE SEQUENCE TABLEC_SEQ START WITH 1;
CREATE SEQUENCE TABLED_SEQ START WITH 1;
CREATE SEQUENCE TABLEE_SEQ START WITH 1;
Java代码:
@Entity
public class TableA {
@Id
private String tableAPk;
@OneToMany(mappedBy="tableBProperty", fetch=FetchType.EAGER, cascade=CascadeType.ALL, orphanRemoval=true)
private List<TableB> tableBs = new ArrayList<TableB>();
public String getTableAPk() {
return tableAPk;
}
public void setTableAPk(String tableAPk) {
this.tableAPk = tableAPk;
}
public List<TableB> getTableBs() {
return tableBs;
}
public void setTableBs(List<TableB> tableBs) {
this.tableBs = tableBs;
}
}
@Entity
public class TableB {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="TABLEB_SEQ")
@SequenceGenerator(sequenceName = "TABLEB_SEQ", allocationSize = 1, name = "TABLEB_SEQ")
private Integer id;
private String tableBProperty;
@ManyToOne
@JoinColumn(name = "tableBProperty2")
private TableC tableC;
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name="tableBProperty3")
private TableD tableD;
public TableB() {}
public TableB(String tableBProperty, TableC tableC, TableD tableD) {
this.tableBProperty = tableBProperty;
this.tableC = tableC;
this.tableD = tableD;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTableBProperty() {
return tableBProperty;
}
public void setTableBProperty(String tableBProperty) {
this.tableBProperty = tableBProperty;
}
public TableC getTableC() {
return tableC;
}
public void setTableC(TableC tableC) {
this.tableC = tableC;
}
public TableD getTableD() {
return tableD;
}
public void setTableD(TableD tableD) {
this.tableD = tableD;
}
}
@Entity
public class TableC {
@Id private Integer id;
@OneToOne(mappedBy="tableC")
private TableE tableE;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public TableE getTableE() {
return tableE;
}
public void setTableE(TableE tableE) {
this.tableE = tableE;
}
}
@Entity
public class TableD {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="TABLED_SEQ")
@SequenceGenerator(sequenceName = "TABLED_SEQ", allocationSize = 1, name = "TABLED_SEQ")
private Integer id;
@ManyToOne(cascade={CascadeType.PERSIST})
@JoinColumn(name="tableDProperty")
private TableE tableE;
public TableD() {}
public TableD(TableE tableE) {
this.tableE = tableE;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
@Entity
public class TableE {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="TABLEE_SEQ")
@SequenceGenerator(sequenceName = "TABLEE_SEQ", allocationSize = 1, name = "TABLEE_SEQ")
private Integer id;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "tableEProperty")
private TableC tableC;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public TableC getTableC() {
return tableC;
}
public void setTableC(TableC tableC) {
this.tableC = tableC;
}
}
public interface TableARepository extends JpaRepository<TableA, String>{
}
public interface TableCRepository extends JpaRepository<TableC, Integer> {
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class TableARepositoryTest {
private static final Integer TEST_ID = -1;
private static final String TEST_ID_STRING = "TEST1";
@Autowired protected DataSource ds;
@Autowired private TableARepository repoA;
@Autowired private TableCRepository repoC;
protected JdbcTemplate jdbcTemplate;
@Before
public void setUp() throws Exception{
jdbcTemplate = new JdbcTemplate(ds);
String insertASql = "insert into TableA (tableAPk) values (?)";
jdbcTemplate.update(insertASql, new Object[]{TEST_ID_STRING});
String insertCSql = "insert into TableC (id) values (?)";
jdbcTemplate.update(insertCSql, new Object[]{TEST_ID});
String insertESql = "insert into TableE (id, tableEProperty) values (?, ?)";
jdbcTemplate.update(insertESql, new Object[]{TEST_ID, TEST_ID});
}
@After
public void tearDown() throws Exception{
String deleteBSql = "delete from TableB where tableBProperty = ?";
jdbcTemplate.update(deleteBSql, new Object[]{TEST_ID_STRING});
String deleteDSql = "delete from TableD where tableDProperty = ?";
jdbcTemplate.update(deleteDSql, new Object[]{TEST_ID});
String deleteESql = "delete from TableE where ID = ?";
jdbcTemplate.update(deleteESql, new Object[]{TEST_ID});
String deleteASql = "delete from TableA where tableAPk = ?";
jdbcTemplate.update(deleteASql, new Object[]{TEST_ID_STRING});
String deleteCSql = "delete from TableC where ID = ?";
jdbcTemplate.update(deleteCSql, new Object[]{TEST_ID});
}
@Test
public void test() {
TableA tableA = repoA.findById(TEST_ID_STRING).get();
TableC tableC = repoC.findById(TEST_ID).get();
tableA.getTableBs().add(new TableB(TEST_ID_STRING, tableC, new TableD(tableC.getTableE())));
TableA updatedTableA = null;
try {
updatedTableA = repoA.save(tableA);
} catch(Exception e) {
fail("test:"+e.getMessage());
}
assertNotNull(updatedTableA);
assertTrue(Hibernate.isInitialized(updatedTableA.getTableBs().get(0).getTableC()));
}
}
此测试通过,但是如果您检查返回的对象,则它是具有TableC _ $$ _ jvst值的代理。...然后,我的应用程序尝试序列化此对象(我需要)时,它将崩溃。
答案 0 :(得分:0)
将您有问题的实体包裹为:
public static <T> T unproxy(T entity){
Hibernate.initialize(entity)
if(entity instanceof HibernateProxy){
entity = (T)((HibernateProxy)entity).getHibernateLazyInitializer().getImplementation();
} else {
entity = (T)entity
}
return entity;
}
它将返回您未代理的对象。