具有反向外键的单向 @OneToOne

Posted

技术标签:

【中文标题】具有反向外键的单向 @OneToOne【英文标题】:Unidirectional @OneToOne with reversed foreign key 【发布时间】:2015-06-15 17:43:39 【问题描述】:

我们想使用不在主表中但在从表中的外键创建单向@OneToOne 映射。通过提供以下 java 代码,Hibernate 尝试在表 product 中找到列 product_ID,但在 productimage 中找不到。是否可以通过对注释的唯一修改使其工作?

所有不必要的字段和列都已从示例中删除。

JPA 实体:

@Entity
public class Product 

    @Id
    @Column(name = "ID", unique = true)
    private String id;

    // this doesn't work
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "product_ID", nullable = false)
    private ProductImage productImage;

    // this works, but we want one-to-one
    // @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    // @JoinColumn(name = "product_ID", nullable = false)
    // private List<ProductImage> productImages;

    // getters/setters omitted


@Entity
public class ProductImage 

    @Id
    @Column(name = "ID", unique = true)
    private String id;

    @Column
    @Lob
    private Blob data;

    // getters/setters omitted

数据库表:

CREATE TABLE `product` (
  `ID` varchar(255) NOT NULL,
  PRIMARY KEY (`ID`)
)

CREATE TABLE `productimage` (
  `ID` varchar(255) NOT NULL,
  `data` longblob NOT NULL,
  `product_ID` varchar(255) NOT NULL,
  PRIMARY KEY (`ID`),
  KEY `FK_123` (`product_ID`),
  CONSTRAINT `FK_123` FOREIGN KEY (`product_ID`) REFERENCES `product` (`ID`)
)

【问题讨论】:

阅读 @JoinColumn 的 jpa 文档。对于 OneToOne,您应该在用例中使用 referencedColumnName。从性能的角度来看,您应该考虑参考产品表 在对注释进行一组修改后,您最终会得到无效的架构定义。 有时您需要质疑为什么数据库模式是这样的。为什么productimage 引用product,而不是product 引用productimage?如果你真的想要这种模式,为什么不在ProductImage 中定义关联回Product,然后在Product 中使用mappedBy 关联? @DuncanKinnear,该架构是为未来可能出现的情况准备的,即产品将能够拥有多个图像。然后我们将仅将注解更改为@OneToMany 并使用List&lt;ProductImage&gt; 而不是单个Product 引用。我们不想从ProductImage 引用Product,除非真的有必要。 @SamiKorhonen,我试过@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(referencedColumnName = "product_ID", nullable = false) private ProductImage productImage;,但后来出现异常org.hibernate.MappingException: Unable to find column with logical name: product_ID in org.hibernate.mapping.Table(ProductImage) and its related supertables and secondary tables 【参考方案1】:

JPA 实体,更多关于@PrimaryKeyJoinColumn

@Entity
public class Product 
    @Id
    private String id;

    @PrimaryKeyJoinColumn
    @OneToOne(orhanRemoval = true)
    private ProductImage image;


@Entity
public class ProductImage 
    @Id
    private String productId; // this will be foreign key as well as primary

   //other properties goes here

数据库表:

CREATE TABLE product (
    id VARCHAR PRIMARY KEY
);

CREATE TABLE product_image (
    product_id VARCHAR PRIMARY KEY REFERENCES product(id)
    -- other columns goes here
);

【讨论】:

【参考方案2】:

@OneToOne 有点误导。它很可能与您想要的不同。在大多数情况下,经典数据库“一对一”关系是通过 @ManyToOne JPA 注释建模的。尝试一下。通过@ManyToOne 和@JoinColumn 的单向关系从来没有问题。我还会在第二类中明确指定 productId 字段。

【讨论】:

谢谢。如果我在ProductImage 中指定了product 引用,那么它将起作用,但关系将是双向的。另外,也许您的意思是 @OneToManyProduct 类中。 @ManyToOne 我没有成功。 是的。看起来这是一个很好的方法。但是我们必须对 FK 列有一个唯一的约束(如果我们使用它来代替主键连接)。【参考方案3】:

无论您将其映射为@OneToOne 还是@OneToMany,实际上都不存在:客户端只能使用您公开的内容,因此将其映射为@OneToMany 并隐藏实现。

@Entity
public class Product 

    @Id
    @Column(name = "ID", unique = true)
    private String id;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "product_ID", nullable = false)
    private List<ProductImage> productImages;

    //no getters or setters for productImages;

    public ProductImage getProductImage()
         return productImages.size() > 0 ? productImages.get(0) : null;
    

我也没有看到将关系双向设置为 1-2-1 或 1-2-M 的任何特殊问题。同样,如果您不想公开使用 ProductImage > Product 中的引用,请不要公开它。

【讨论】:

“将其映射为@OneToMany 并隐藏实现”——这是我目前的解决方法:-)。使用@OneToOne @JoinColumn(name = "product_ID", insertable = false, updatable = false) private ProductImage productImage; 我仍然收到错误org.hibernate.HibernateException: Missing column: product_ID in acme.product 我没有看到 1-2-1 或 1-2-m 之间在数据库访问方面有任何实际区别,所以为什么不直接使用它或使其成为双向 1-2-1 .正如我所说,没有客户端代码需要知道这是如何实现的。

以上是关于具有反向外键的单向 @OneToOne的主要内容,如果未能解决你的问题,请参考以下文章

微风:尽管定义了 invForeignKeyNames,但仍然没有填充复合外键的单向一对多导航

hibernate 之 关联映射的基于外键的单向一对一映射

django 查询具有外键的模型,检查该外键的属性

Hibernate - OneToMany 单向映射 - SQLGrammarException

具有该实体外键的学说实体

删除具有外键的列