JPA:复制简单与关系映射 - 在哪里放置insertable = false,updatable = false以及为什么

时间:2017-05-17 09:15:15

标签: hibernate jpa eclipselink openjpa datanucleus

这是Hibernate: Where do insertable = false, updatable = false belong in composite primary key constellations involving foreign keys?的后续问题:

考虑以下实体映射:

public class Zip {

    @ManyToOne
    @JoinColumn(name = "country_code", referencedColumnName = "iso_code")
    private Country country = null

    @Column(name = "country_code")
    private String countryCode;

    ...
}

就像这样,JPA实现会扼杀类似于"乡村代码的重复映射,只有其中一个可以被指定为可写"。

为什么关系只读private Country country)首选/通常将只读放在简单ID字段上({{ 1}})?

为什么一个人在实践中优于另一个人(优点/缺点)?

我唯一能想到的是,当数据库使用任何FK时,使用可写关系会更好,这会使实体在某种程度上是强制性的,但这不会阻止用户从能够将新实体插入到具有未知ID的DB中,这将使可写关系稍微安全一些。能够使用ID当然会使数据库中的完整实体加载冗余,这可能是一个很大的性能方面。

欢迎更多参数。

PS:我将JPA实现添加为标签以吸引更多观众。

1 个答案:

答案 0 :(得分:2)

首先,没有真正需要countryCode映射,因为其中的数据保存在引用的国家/地区,在iso_code的映射中。例如,EclipseLink可以在查询中使用zip.country.id = :isoCode,并且知道它可以直接使用country_code外键而无需加入表,就像使用zip.countryCode = :isoCode一样。因此,如果您同时拥有它们,那么您应该有理由,并且该原因应该决定您希望控制哪个country_code外键。

其次,如果数据库没有外键约束,那么建立关系对你没有任何帮助。没有限制,如果您从数据库中删除国家/地区,则Zip仍会引用该国家/地区。如果它不在缓存中,则countryCode将具有值,但引用将为null(或根据提供程序抛出错误)。

我也不同意关系应该是只读的;我相信可能这样做可以在数据库中更改关系,而无需在引用的对象中读取IMO是一种不好的做法。 JPA允许2层缓存,因此更改将导致缓存关系与数据库不同步,然后需要额外的开销来解决。如果您打算这样做,您可能根本不会映射country关系引用 - 如果/需要时从JPA读取它并将其作为瞬态存储在实体中(如果有意义的话)。

最后,您的对象模型应该映射您的业务需求。仅仅因为数据库有引用和字段,并不意味着你的Java实体也必须以完全相同的方式映射它们。