编辑:解决了,但我不知道现在有什么不同。如果有人能解释发生了什么不同的事情,我将不胜感激。
它现在的工作方式是只合并父项,而不是子项,如下所示:
Parent parent = child.getParent();
parent.getChildren().add(child);
getJpaTemplate().merge(parent);
现在,它似乎正在工作,但我不太明白为什么这会奏效,而我之前的尝试却没有。
原始尝试/问题:
我遇到了 Spring JPA 和 IndirectSets 的问题。我有两个实体,Parent 和 Child,定义如下。我有一个 Spring 表单,我正在尝试创建一个新的 Child 并将其链接到现有的 Parent,然后将所有内容都反映在数据库和 Web 界面中。发生的事情是它被放入数据库,但 UI 似乎不同意。
在 OneToMany 关系中相互链接的两个实体如下所示:
@Entity
@Table(name = "parent", catalog = "myschema", uniqueConstraints = @UniqueConstraint(columnNames = "ChildLinkID"))
public class Parent {
private Integer id;
private String childLinkID;
private Set<Child> children = new HashSet<Child>(0);
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "ChildLinkID", unique = true, nullable = false, length = 6)
public String getChildLinkID() {
return this.childLinkID;
}
public void setChildLinkID(String childLinkID) {
this.childLinkID = childLinkID;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parent")
public Set<Child> getChildren() {
return this.children;
}
public void setChildren(Set<Child> children) {
this.children = children;
}
}
@Entity
@Table(name = "child", catalog = "myschema")
public class Child extends
private Integer id;
private Parent parent;
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ChildLinkID", referencedColumnName = "ChildLinkID", nullable = false)
public Parent getParent() {
return this.parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
当然,它们每个都有各种简单的属性。现在,问题是当我从 Spring 界面编辑这些简单属性时,一切都运行良好。我可以保留这些类型的新实体,并且它们会在使用 JPATemplate 进行查找时出现,例如,所有父母 (getJpaTemplate().find("select p from Parent p")) 或单个实体的 ID 或另一个财产。
我遇到的问题是,现在,我正在尝试通过父页面的链接创建一个链接到现有父的新子。这是控制器的重要部分(请注意,我已将 JPA foo 放在控制器中以使其更清晰;实际的 JpaDaoSupport 实际上在另一个类中,适当分层):
protected Object formBackingObject(HttpServletRequest request) throws Exception {
String parentArg = request.getParameter("parent");
int parentId = Integer.parseInt(parentArg);
Parent parent = getJpaTemplate().find(Parent.class, parentId);
Child child = new Child();
child.setParent(parent);
NewChildCommand command = new NewChildCommand();
command.setChild(child);
return command;
}
protected ModelAndView onSubmit(Object cmd) throws Exception {
NewChildCommand command = (NewChildCommand)cmd;
Child child = command.getChild();
child.getParent().getChildren().add(child);
getJpaTemplate().merge(child);
return new ModelAndView(new RedirectView(getSuccessView()));
}
就像我说的那样,我可以浏览表格并为孩子填写新值——甚至不显示父母的详细信息。当它返回到控制器时,它会通过并将其保存到底层数据库,但接口永远不会反映它。一旦我重新启动应用程序,它就在那里并适当地填充。
我能做些什么来解决这个问题?我试图调用额外的合并,尝试刷新(这给出了一个事务异常),除了编写我自己的数据库访问代码之外的一切。我已经确保每个类都有一个适当的 equals() 和 hashCode(),有完整的 JPA 调试以查看它是否进行了适当的 SQL 调用(它似乎没有对子表进行任何新的调用)并逐步通过调试器(正如预期的那样,它都在 IndirectSets 中,并且在保存和显示父对象之间,对象采用新的内存地址)。我的下一步是什么?