当前位置: 首页 > 面试题库 >

我是否必须为双向关系设置双方?

徐奇
2023-03-14
问题内容

@Entity
public class A {
@GeneratedValue
@Id
private long id;

    public long getId() {
        return id;
    }

    public void setId(final long id) {
        this.id = id;
    }

    @OneToMany(mappedBy = "a")
    List<B> bs;

    public List<B> getBs() {
        return bs;
    }

    public void setBs(final List<B> bs) {
        this.bs = bs;
    }
}
@Entity
public class B {
    @GeneratedValue
    @Id
    private long id;

    public long getId() {
        return id;
    }

    public void setId(final long id) {
        this.id = id;
    }

    @ManyToOne
    @JoinTable
    A a;

    public A getA() {
        return a;
    }

    public void setA(final A a) {
        this.a = a;
    }
}

建立关系,我必须打电话

b.setA(a);
a.getBs().add(b);

为什么两者都是必要的,为什么仅仅做是不够的

b.setA(a);

要么

a.getBs().add(b);

该关系存储在联接表中,b.setA(a)并将更新该联接表。

但是当我之后进行查询时,它a.getBs()为空。这是为什么?

这是一个测试案例,说明了这个问题。请注意,最后一个断言失败。

public class QuickTestAB2 {

    private static String dbUrlBase = "jdbc:derby:testData/db/test.db";

    private static String dbUrlCreate = dbUrlBase + ";create=true";

    private static String dbUrlDrop = dbUrlBase + ";drop=true";

    private EntityManagerFactory factory;

    private EntityManager em;

    public Map<String, String> createPersistenceMap(final String dbUrl) {
        final Map<String, String> persistenceMap = new HashMap<>();
        persistenceMap.put("javax.persistence.jdbc.url", dbUrl);
        return persistenceMap;
    }

    public void dropDatabase() throws Exception {
        if (em != null && em.isOpen()) {
            em.close();
        }
        if (factory != null && factory.isOpen()) {
            factory.close();
        }
        try (Connection conn = DriverManager.getConnection(dbUrlDrop)) {

        } catch (final SQLException e) {
            // always

        }
    }

    public void deleteDatabase() throws Exception {
        dropDatabase();
        final File file = new File("testData/db/test.db");
        if (file.exists()) {
            FileUtils.forceDelete(file);
        }
    }

    public void createNewDatabase() throws SQLException, IOException {

        FileUtils.forceMkdir(new File("testData/db"));
        try (Connection conn = DriverManager.getConnection(dbUrlCreate)) {

        }
    }

    @BeforeClass
    public static void setUpBeforeClass01() throws Exception {
        Tests.enableLog4J();
        JPATests.enableJPA();

    }

    @AfterClass
    public static void tearDownAfterClass01() throws Exception {

    }

    @Before
    public void setUp01() throws Exception {

        deleteDatabase();
        createNewDatabase();
        final Map<String, String> map = createPersistenceMap(dbUrlCreate);
        factory = Persistence.createEntityManagerFactory("pu", map);

    }

    @After
    public void tearDown01() throws Exception {
        if (em != null && em.isOpen()) {
            em.close();
        }
        em = null;
        if (factory != null && factory.isOpen()) {
            factory.close();
        }
        factory = null;
    }

    @Test
    public void test01() throws Exception {
        em = factory.createEntityManager();
        final A a = new A();
        final B b = new B();
        b.setA(a);
        try {
            em.getTransaction().begin();
            em.persist(a);
            em.persist(b);
            em.getTransaction().commit();
        } finally {
            em.close();
        }
        em = factory.createEntityManager();
        B b2;
        A a2;
        try {
            em.getTransaction().begin();
            Query q = em.createQuery("SELECT b FROM B b");
            b2 = (B) q.getSingleResult();
            q = em.createQuery("SELECT a FROM A a");
            a2 = (A) q.getSingleResult();
            em.getTransaction().commit();
        } finally {
            em.close();
        }
        assertThat(a2, is(not(nullValue())));
        assertThat(b2, is(not(nullValue())));

        assertThat(b2.getA(), is(not(nullValue())));
        assertThat(a2.getBs().isEmpty(), is(false));

    }

}

动机: 当数量增加时,通过更改“仅一侧”来更改双向关系会很有用a.Bs。在这种情况下,UPDATE SELECT拥有方的查询比调用a.getBs().remove(b) See


问题答案:

如下面NikosParaskevopoulos的回答所述,JPA和Java对象要求您设置关系的双方。只要设置了拥有方,数据库就会随着关系的变化而更新,但是非拥有方仅在手动设置数据库或强制刷新或重新加载数据库时才会反映数据库中的内容。从单独的上下文中读取实体不会强制重新加载,因为您的JPA提供程序可以使用二级缓存。这是EclipseLink中的默认设置。您的其他读取是从共享缓存中返回A,与原始对象一样,它没有将B添加到其B列表中。

最简单的解决方案是将B预先设置为A的列表。但是,这里的其他选项是使用em.refresh(a)或查询提示来强制A的刷新,或者禁用共享的缓存。



 类似资料:
  • 我试图在用户和地址之间建立双向关系, 用户1-------->*地址 但是 地址1-------->1个用户 我在上网时得到了这些信息 > 对于一对一双向关系,拥有方对应于包含对应外键的方 双向关系的反向侧必须通过使用OneToOne、 OneToMany或ManyToMany批注的mappedBy元素来引用其 所属侧。mappedBy元素指定作为 关系所有者的实体中的属性或字段。 但如果我按照情

  • 问题内容: 假设我有两个实体: 然后,我要保留“客户”实体,然后,参照先前添加的“客户”保留“订单”实体。当我从数据库中检索此客户并调用getOrders时,它将返回空集。这是正常行为吗?如果是,当我添加新的Order实体时,我该怎么做以自动刷新此集合? 问题答案: Jpa不会为您维护关系,因此应用程序需要设置双向关系的两端,以使它们与数据库保持同步。当您设置了order-> customer关系

  • 我在将带有@ManyToOne关系的实体(雇员)映射到带有@OneToMany关系的实体(社区)时遇到了问题。 当我将一个实体(社区)分配给一个实体(员工),其中社区的值为空时,它工作正常。 问题出现了,如果雇员已经为社区分配了价值。当我更改该值并保存更改时,该员工为社区获得了新的值,并且这个新社区在集合中获得了该员工。唯一的问题是,老社区仍然有这个员工在收集,但它应该被删除。这只有在数据库重新启

  • 我正在浏览关于双向关系的Hibernate文档,文档中说: 例7.21。双向一对多,多对一为协会所有者 部队通过部队财产与士兵有双向的一对多关系。您不必(不得)在mappedBy side中定义任何物理映射。 要将双向一对多映射为一对多,并将一对多的一端作为拥有端,您必须删除mappedBy元素,并将多对一@JoinColumn设置为可插入且可更新为false。此解决方案未经优化,将生成其他更新语

  • 问题内容: 我使用的是用这样的: 我只关门了。我是否还需要关闭()? 问题答案: 不,您只需要关闭最外面的流。它将一直委托给包装的流。 但是,您的代码包含一个概念上的失败,应该在中发生关闭,否则当代码在打开和关闭之间引发异常时,它永远不会关闭。 例如 (请注意,我更改了代码以 引发 异常,以便您了解问题的原因,该异常即包含有关问题原因的详细信息) 或者,当您已经在使用Java 7时,也可以使用AR

  • 我很难找到如何在Spring中从@manytomany关系中检索数据。我遇到了无限递归问题,并尝试了一些解决方案,比如使用@JSONIgnoreProperties,但都没有成功。 一个用户可以有多个组,一个组可以有多个用户。我可以将用户添加到组中,但是当涉及到检索与用户关联的所有组时,我会从无限递归中得到堆栈溢出。 理想情况下,我希望能够发送带有用户ID的get请求,然后检索与该用户关联的所有G