具有反向外键的单向 @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<ProductImage>
而不是单个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
引用,那么它将起作用,但关系将是双向的。另外,也许您的意思是 @OneToMany
在 Product
类中。 @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,但仍然没有填充复合外键的单向一对多导航