【问题标题】:JPA IndirectSet changes not reflected in Spring frontendJPA IndirectSet 更改未反映在 Spring 前端
【发布时间】:2011-02-14 01:09:58
【问题描述】:

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

它现在的工作方式是只合并父项,根本不合并子项,如下所示:

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 中,并且在保存和显示父对象之间,对象采用新的内存地址)。我的下一步是什么?

【问题讨论】:

    标签: spring orm jpa spring-mvc toplink-essentials


    【解决方案1】:

    不确定这与您的问题有关,但为什么您的 Parent 类中有 childLinkID 属性?这看起来很奇怪,特别是因为您使用相应的列进行连接。我想知道这个映射如何工作,我会解决这个问题。你可以不试试(也去掉referencedColumnName,你不需要这个)?

    顺便说一句,你为什么不在ParentChild之间用同样的方法设置链接的两边呢?这使得代码难以阅读和维护 IMO。


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

    【讨论】:

    • 原因是在导致问题的真实模型中,我将其简化为,我有真实世界的数据需要作为父类的属性单独使用,这是这里对孩子的直接映射。事实上,我必须实现另外两个子类,每个子类都引用父类的 /different/ 属性。 (我没有设计数据模型来阻止您的下一个问题/建议。)要回答第二个问题,这是因为我添加了从父级到子级的链接来解决这个问题(并在修复它的同时)。这在实际代码中发生了变化。
    • 我还更改了实体,以便将 JPA 注释从 getXXX 方法移动到变量声明本身,我没有提及。这也能解决问题吗?
    • @Jon 1) 我不确定我是否理解 childLinkID 属性的必要性,我想知道 JPA 如何处理整个事情 2) "这是因为我添加了来自父级的链接将孩子作为解决此问题的方法” - 这是双向关联的必需,您必须设置链接的两侧。 3) “我还更改了实体,因此我将 JPA 注释从 getXXX 方法移动到变量声明本身” - 这不会改变任何东西。实际上,我仍然认为有一些深奥的东西,并且改变级联可以解决它。
    • 我可能无法理解您的问题。在我的真实模型中,childLinkID 是一个业务逻辑变量。它也恰好是另一个表的外键引用。那应该会造成困难吗?
    • 有趣的是,删除引用的ColumnName,我得到:内部异常:com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:无法添加或更新子行:外键约束失败(myschema. child,约束 fk_child_parent 外键 (ChildLinkID) 引用 parent (ChildLinkID) 删除时不执行更新不执行操作)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-03
    • 2019-09-10
    • 1970-01-01
    • 2011-11-05
    • 2014-09-03
    • 2014-07-12
    相关资源
    最近更新 更多