Java 提交JSP表单时,与Hibernate的一对一关系出现共享密钥错误

Java 提交JSP表单时,与Hibernate的一对一关系出现共享密钥错误,java,hibernate,spring-mvc,Java,Hibernate,Spring Mvc,我试图创建两个表,第一个表有主键,另一个表有主键。我使用的是Spring mvc+hibernate,在提交jsp表单时显示了以下错误: 试图从空的一对一属性[model.TableB.resource]分配id;嵌套异常为org.hibernate.id.IdentifierGenerationException:尝试从空的一对一属性[model.TableB.resource]分配id 表A: @Entity public class TableA{ @Id private

我试图创建两个表,第一个表有主键,另一个表有主键。我使用的是Spring mvc+hibernate,在提交jsp表单时显示了以下错误:

试图从空的一对一属性[model.TableB.resource]分配id;嵌套异常为org.hibernate.id.IdentifierGenerationException:尝试从空的一对一属性[model.TableB.resource]分配id

表A:

@Entity
public class TableA{

    @Id
    private String sNum

    @OneToOne(mappedBy = "resource",cascade = CascadeType.ALL)
    private TableB tableB;

    //other fields, getter setters
}
表B:

@Entity
public class TableB{

    @Id
    private String id

    @MapsId
    @OneToOne
    @JoinColumn(name="resourceId")
    private TableA resource;

    //other fields, getter setters
}
这些实体将以下内容输出到mysql中:

TableA
+------+---------------+---------------+-----------------+
| sNum | column1tableA | column2tableA | ..other columns |
+------+---------------+---------------+-----------------+
| PK   |               |               |                 |
+------+---------------+---------------+-----------------+


TableB
+-------------------+---------+-----------------+
|    resourceId     | column1 | ..other columns |
+-------------------+---------+-----------------+
| PK FK from TableA |         |                 |
+-------------------+---------+-----------------+
服务:

public class tableAService {
    @Autowired
    TableARepository tableARepository; //this repository extends from jpa repository

    public void create(TableA tableA){
    tableARepository.save(tableA); 
    }
}
控制器:

@RequestMapping(value = "/createTableA", method = RequestMethod.GET)
public String getCreateTableAPage(Model model){
    if(!model.containsAttribute("tableA"))
        model.addAttribute("tableA", new TableA());

    return "createTableA";
} // this returns the registration page

@RequestMapping(value="/doCreateRe", method = RequestMethod.POST)
public String doCreateRe(@Valid @ModelAttribute("tableA") TableA tableA, BindingResult result){
    if(result.hasErrors()){

        return "redirect:/createPage";
    }try{
        myservice.create(tableA);
        return "viewPage";
    }catch(Exception e){
        System.out.println(e.getMessage());
        return "error";
    }
} // this handles the onsubmit of the registration page
编辑-2(参见下面的示例输出):提交表单时,表A的字符串id(用户在表单上手动输入)应保存为表B上的外键。例如,我想保存一个tableA类型的对象,我将在jsp表单上手动分配它的id,填充同一页面/表单上的其他tableA字段以及表单上也存在的相关tableB对象(即tableA.tableB.someField)(提交“注册”表格后,将在表a和表B上创建新行,表B的键将是表a中的键-见下文)

createTableA页面JSP:

<form:form  modelAttribute="tableA" method="POST" action="doCreateRe">
  ...
 <form:input path="sNum" required="true"/> <!-- sample input is abc123 -->
 <form:input path="column1tableA" required="true"/> <!-- sample input is chocolate -->
 <form:input path="column2tableA" required="true"/> <!-- sample input is beer -->
 <form:input path="tableB.column1" required="true"/> <!-- sample input is isDelicious -->
 <form:input path="tableB.column2" required="true"/> <!-- sample input is isBetter -->
 ...
</form:form>
表B:

+------------+-------------+----------+
| resourceId |   column1   | column2  |
+------------+-------------+----------+
| abc123 FK  | isDelicious | isBetter |
+------------+-------------+----------+ 

问题可能是TableB实际上没有针对资源设置TableA

因此,在您的创建服务代码中,您应该具有以下内容:

tableB.setResource(tableA);
检查您的创建代码并进行上面的更改,它将起作用

也有潜力 另一个问题可能是tableB对象未在tableA中初始化,因此当提交失败时

在tableA类中,尝试以下操作:

@OneToOne(mappedBy = "resource",cascade = CascadeType.ALL)
private TableB tableB = new TableB();
或在构造函数中:

this.tableB = new TableB();
另一种尝试方法是删除:

@MapsId
在表B中,从资源字段。即:

@MapsId
@OneToOne
@JoinColumn(name="resourceId")
private TableA resource;
换成

@OneToOne
@JoinColumn(name="resourceId")
private TableA resource;

好吧,我终于找到了解决办法。为了

在TableA实体上,我需要为其setter添加额外的一行

@Entity
public class TableA{

    @Id
    private String sNum

    @OneToOne(mappedBy = "resource",cascade = CascadeType.ALL)
    private TableB tableB;

    public TableB getTableB() {         
        return tableB;
    }

    public void setTableB(TableB tableB) {
        this.tableB = tableB;
        tableB.setResource(this); // added this line of code
    }

    //other fields, getter setters
 }

我的服务包含tableA存储库中的save方法。该表单具有tableA的modelAttribute,并且它还需要保存与其相关的tableB字段。我将如何完成此操作?(请参阅编辑)我尝试在controller中的服务之前创建table2的新实例,并将其设置为asset,但它仍然不起作用,您的解决方案也是如此;我了解到设置为optional=false会修复某些问题,但不幸的是,相同的结果发现了第三个可能的原因,希望是一个修复。请检查我的重新编辑。您是否尝试了第三个修复?我已经完成了在我的代码上进行了测试,效果很好。是的,我明白你的意思,但我需要为tableB分配一个新id。如果我使用你的第三个建议,我编辑了我的问题以进行澄清
@Entity
public class TableA{

    @Id
    private String sNum

    @OneToOne(mappedBy = "resource",cascade = CascadeType.ALL)
    private TableB tableB;

    public TableB getTableB() {         
        return tableB;
    }

    public void setTableB(TableB tableB) {
        this.tableB = tableB;
        tableB.setResource(this); // added this line of code
    }

    //other fields, getter setters
 }