当前位置: 首页 > 知识库问答 >
问题:

为什么要区分orm中双向关系的一方为拥有方?

屠锐
2023-03-14

在一对多关系中,通常使用@ManyToOne注释的字段是所有者-另一方具有“mappedBy”属性。但是,如果我跳过“mappedBy”并用@JoinColumn(同一列)注释两侧,我可以更新两侧-更改将传播到db。

我没有两个单向关系而不是一个双向关系-只有一个连接列。

没有选择一方作为关系所有者会遇到什么问题?

我的实体看起来类似于以下内容:

@Entity
public class B {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long id;


   @ManyToOne
   @JoinColumn(name = "parent_id")
   @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
   private B parent;

   @OneToMany()
   @JoinColumn(name = "parent_id")
   @Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})
   private List<B> children = new ArrayList<B>();
...
}

它似乎对性能没有任何影响(至少看起来不错),下面是一个简单的测试和日志输出:

Session session = HibernateUtil.getSessionFactory().openSession();
    session.beginTransaction();
    B a = new B("a");
    B b = new B("b");
    B c = new B("c");
    B d = new B("d");
    B e = new B("e");
    session.save(a);
    session.save(b);
    session.save(c);
    session.save(d);
    session.save(e);
    session.getTransaction().commit();
    System.out.println("all objects saved");
    session.beginTransaction();
    a.getChildren().add(b);
    a.getChildren().add(c);
    session.save(a);
    session.getTransaction().commit();
    System.out.println("b and c added as children");
    session.beginTransaction();
    a.getChildren().add(d);
    a.getChildren().add(e);
    session.getTransaction().commit();
    System.out.println("e and f added as children");
    session.close();

Hibernate: insert into B (fieldInB, parent_id) values (?, ?)
Hibernate: insert into B (fieldInB, parent_id) values (?, ?)
Hibernate: insert into B (fieldInB, parent_id) values (?, ?)
Hibernate: insert into B (fieldInB, parent_id) values (?, ?)
Hibernate: insert into B (fieldInB, parent_id) values (?, ?)
all objects saved
Hibernate: update B set parent_id=? where id=?
Hibernate: update B set parent_id=? where id=?
b and c added as children
Hibernate: update B set parent_id=? where id=?
Hibernate: update B set parent_id=? where id=?
e and f added as children

共有3个答案

韩楷
2023-03-14

这将是低效的,因为保存B将导致

  • 更新对象B
  • 将所有子对象的父引用更新到对象B
  • 级联到更新其父引用的对象B的所有子对象

而不是

  • 更新对象B
  • 级联到对象B的所有子类,它们更新其父引用
尹承泽
2023-03-14

我认为这篇文章可能会有所帮助,特别是我在下面提到的内容:

什么是使单向不等于双向的“东西”?当我们有单向关系时,只有Customer类引用User类;您只能按客户获取用户。getUser()您不能用另一种方法。当我们编辑我们的用户类时,我们允许用户获取客户用户。getCustomer()。

你也可以检查一下这个问题。

这个问题看起来也很有帮助。

主要的区别是双向关系在两个方向上提供导航访问,这样您就可以在没有显式查询的情况下访问另一方。它还允许您将级联选项应用于两个方向。

关于这个话题还有很多问题。这些将对您非常有帮助:)

赵驰
2023-03-14

您看不到额外的SQL语句,因为您没有正确设置关联的双方。例如,你说:

a.getChildren().add( b );

并假设ab现在是关联的。但是当您在这里调用b.getParent()时会发生什么?假设此代码“将b作为子级添加到a”,然后返回此新子级b,调用方希望导航b.getParent()

相反,你应该做的是:

a.getChildren().add( b );
b.setParent( a );

现在,您的惯用Java代码继续工作(b.get父母()行为正常)。现在,您将在这里看到多个SQL语句。这就是为什么你需要选择一方作为“主人”。

此外,尽管完全是无稽之谈,但请考虑:

a.getChildren().add( b );
b.setParent( c );

这里写入数据库的是什么?双方实际上为b指定了不同的父级。那么我们相信什么呢?

 类似资料:
  • 我在实体“任务”和实体“用户”之间有双向关联。 “任务”定义如下 “用户”的定义是 从两个方向访问关系很好。问题是,一旦定义了“Task”实体,我就无法更新它。 这是一个测试案例 我做错了什么?

  • 问题内容: 拥有方 到底是什么意思?一些映射示例( 一对多,一对一,多对一 )的解释是什么? 以下文本摘录自Java EE 6文档中 @OneToOne 的描述。您可以在其中看到概念 拥有的一面 。 定义与另一个具有一对一多重性的实体的单值关联。通常不必显式指定关联的目标实体,因为通常可以从被引用对象的类型中推断出该目标实体。如果关系是双向的, 则非拥有方 必须使用OneToOne批注中的mapp

  • 问题内容: 拥有方到底是什么意思?一些映射示例(一对多,一对一,多对一)的解释是什么? 以下文本摘录自Java EE 6文档中@OneToOne的描述。您可以在其中看到概念拥有方面。 定义与另一个具有一对一多重性的实体的单值关联。通常不必显式指定关联的目标实体,因为通常可以从被引用对象的类型中推断出该目标实体。如果关系是双向的,则非拥有方必须使用OneToOne批注中的mappingBy元素来指定

  • 如果是使用Spring数据/JPA的拥有方,用双向关系表示下表的最佳方式是什么?我希望能够使用保存,并保存。 节点表 身份证 node_node表 > 节点标识2 这是我到目前为止所拥有的。以为拥有方的双向关系,这意味着当我在

  • 问题内容: 我有一个带有和对象的简单模型。 一个问题有很多选择。 许多选择有一个问题 有两种使用Hibernate来实现的方法 实施一:所有者是选择 Question.java Choice.java 实施二:所有者方是质询 Question.java Choice.java 两种实现之间有什么区别? 问题答案: 第一个示例是正常且正确的双向一对多/多对一映射。设置为-attribute(“拥有方

  • 问题内容: @Entity public class A { @GeneratedValue @Id private long id; 建立关系,我必须打电话 为什么两者都是必要的,为什么仅仅做是不够的 要么 ? 该关系存储在联接表中,并将更新该联接表。 但是当我之后进行查询时,它为空。这是为什么? 这是一个测试案例,说明了这个问题。请注意,最后一个断言失败。 动机: 当数量增加时,通过更改“仅一