Spring前端中未反映JPA间接集更改

Spring前端中未反映JPA间接集更改,spring,orm,jpa,spring-mvc,toplink-essentials,Spring,Orm,Jpa,Spring Mvc,Toplink Essentials,编辑:解决了,但我不知道现在有什么不同。如果有人能以不同的方式解释发生的事情,我将不胜感激 它现在的工作方式是只合并父对象,而不合并子对象,如下所示: Parent parent = child.getParent(); parent.getChildren().add(child); getJpaTemplate().merge(parent); 现在,它似乎起作用了,但我不太明白为什么这会起作用,而我以前的尝试没有 原始尝试/问题: 我对Spring JPA和IndirectSets有意见

编辑:解决了,但我不知道现在有什么不同。如果有人能以不同的方式解释发生的事情,我将不胜感激

它现在的工作方式是只合并父对象,而不合并子对象,如下所示:

Parent parent = child.getParent();
parent.getChildren().add(child);
getJpaTemplate().merge(parent);
现在,它似乎起作用了,但我不太明白为什么这会起作用,而我以前的尝试没有

原始尝试/问题:

我对Spring JPA和IndirectSets有意见。我有两个实体,父实体和子实体,定义如下。我有一个Spring表单,在这个表单中,我试图创建一个新的子对象并将其链接到一个现有的父对象,然后将所有内容都反映在数据库和web界面中。发生的事情是,它被放入数据库,但用户界面似乎不同意

在一对一关系中相互链接的两个实体,如下所示:

@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;
    }
}
就像我说的,我可以浏览表单并为孩子填写新的值——甚至不显示家长的详细信息。当它返回到控制器时,它会遍历并将其保存到底层数据库,但接口从未反映它。一旦我重新启动应用程序,它就在那里,并进行了适当的填充

我能做些什么来澄清这个问题?除了编写自己的数据库访问代码之外,我还尝试调用额外的合并、尝试刷新(这会导致事务异常)。我已经确保每个类都有一个适当的equals()和hashCode(),启用完整的JPA调试,以查看它正在进行适当的SQL调用(它似乎没有对子表进行任何新的调用),并在调试器中逐步执行(正如预期的那样,它都在间接集中,并且在保存和显示父对象之间,对象采用新的内存地址)。我的下一步是什么?

我不确定这是否与您的问题有关,但为什么您的
父类中有
childLinkID
属性?这看起来很奇怪,特别是因为您正在使用对应的列进行连接。我想知道如何处理此映射,我会解决此问题。您能y不带(同时删除
referencedColumnName
,您不需要这个)

顺便问一下,为什么不用相同的方法设置
父项
子项
之间链接的两侧?这使得代码很难阅读和维护


您在我回答问题时编辑了该问题,并将层叠从
父级
更改为
子级
,但这看起来像是真正问题的解决方法,我不确定您是否会面临其他问题。请尝试按照我的建议修复您的映射。

我不确定这与您的问题有关,但您为什么要这样做在您的
父类中是否存在
childLinkID
属性?这似乎很奇怪,尤其是因为您正在使用对应的列进行连接。我想知道如何处理此映射,我会解决此问题。您是否可以尝试不使用此属性(同时删除
ReferenceColumnName
,您不需要此属性)

顺便问一下,为什么不用相同的方法设置
父项
子项
之间链接的两侧?这使得代码很难阅读和维护



您在我回答问题时编辑了该问题,并将级联从
Parent
更改为
Child
,但这看起来像是解决实际问题的方法,我不确定您是否会遇到其他问题。请尝试按照我的建议修复映射。

原因是在导致问题的实际模型中,我模拟了这个问题有鉴于此,我有真实世界的数据需要单独用作父类的属性,这是到子类的直接映射。事实上,我还必须实现另外两个子类,每个子类都引用父类的/不同/属性。(我设计数据模型不是为了阻止你提出下一个问题/建议。)回答第二个问题,是因为我添加了从家长到孩子的链接,作为解决这个问题的方法(并且在解决问题的同时)。这在实际代码中发生了变化。我还更改了实体,因此我将JPA注释从getXXX方法移动到变量声明本身,我忽略了这一点。这也解决了这个问题吗?@Jon 1)我不确定我是否理解使用
childLinkID
属性的必要性,我想知道JPA是如何处理整个事情的2)“这是因为我添加了从父级到子级的链接来解决这个问题”-这是双向关联所必需的,您必须设置链接的两侧。3) “我还更改了实体,以便将JPA注释从getXXX方法移动到变量声明本身”——这不会改变任何东西。事实上,我仍然认为这里面有一些深奥的东西,改变层叠结构可以解决这个问题。我可能不理解你的问题。在我的真实模型中,childLinkID是一个业务逻辑变量。它也恰好是另一个表的外键引用。这会导致困难吗?有趣的是,删除referencedColumnName,我得到:内部异常:com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:无法添加或更新子行:外键约束失败(
myschema
child
,CONSTRAINT
fk_child\u parent
外键(
ChildLinkID
)引用
parent
ChildLinkID
)关于删除无操作关于更新无操作)原因是,在引起问题的真实模型中,我将其简化为这样,我有真实世界的数据需要作为父类的属性单独使用,父类是到子类的直接映射。事实上,我还必须实现另外两个子类,每个子类都引用家长。(我没有设计数据模型,只是为了避开你的下一个问题。)
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()));
}