首页 > 解决方案 > 如何使用 Hibernate 基于现有列填充集合

问题描述

我有两个具有属性的现有表(someField在示例代码中)。

我想要做的:用与我正在加载的实体具有相同值的Foo.bars所有实体填充集合。BarsomeFieldFoo

我不想创建额外的连接表,因为我不想显式更新关系。

我如何通过实体和/或其字段上的注释来实现这一点?

一些澄清:

  1. 这两someField列是独立修改的。
  2. 两列中的任何一列都没有唯一键约束(这就是我添加 的原因@ManyToMany)。
  3. 我不需要外键关系或任何级联。
  4. 如果修改了集合,则不应更新列。我希望休眠只在加载Foo实体时填充集合。
  5. 我尝试@JoinFormula在没有任何@XtoY关系的情况下使用,但无法正常工作。
  6. 该关系仅从一侧建模,因为Foo如果我有Bar实例,我从不关心 s。

我正在使用 spring-boot-starter-data-jpa 2.3,它使用 Hibernate 5.4.15

@Entity
public class Foo{

  @Id
  @GeneratedValue
  private int id;

  private int someField;

  @ManyToMany
  private Set<Bar> bars;

}

@Entity
public class Bar{

  @Id
  @GeneratedValue
  private int id;

  private int someField;

}

2020 年 6 月 22 日更新

由于我无法表达我的用例,我创建了一个最小的github 项目

我发现实现所需行为的唯一两种方法是:

  1. 实现Bar手动加载关联实例的显式控制器逻辑。

  2. 实现一个附加到手动获取关联实例的FooRepository加载方法的 AspectJ 方面。Bar

两者都“错了”,因为我认为这属于 hibernate 的范围,它会创建很多额外的数据库查询。

标签: javahibernatespring-data-jpa

解决方案


所以首先,我不明白你为什么要使用@ManyToMany,因为那是用于 n 对 n 关系而你的看起来不像那样。

您可以通过两种方式对父子关系进行建模,最有效的一种是 ManyToOne 映射,其中子代管理父代的外键:

@Entity
public class Parent {

  @Id
  @GeneratedValue
  private int id;

  private int someField;

}

@Entity
public class Child {

  @Id
  @GeneratedValue
  private int id;

  private int someField;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(
    name = "someField",
    referencedColumnName = "someField",
    unique = false,
    updateable = false,
    insertable = false)
  private Parent parent;

}

你可以使用 JPQL/Criteria Queries 来获取你需要的一切。

阅读有关多对一关联的更多信息。还有更多

有关“唯一”等属性,请参阅@JoinColumn 文档。

如果你坚持反过来做,那也可以:

@Entity
public class Parent {

  @Id
  @GeneratedValue
  private int id;

  private int someField;

  @OneToMany(
    // cascade = What operations do you want to cascade? Who is the owner of the relationship?
    // orphanRemoval = Do you want to delete orphaned children?
  )
  @JoinColumn(name = "someField",
    unique = false,
    updateable = false,
    insertable = false)
  private List<Child> children = new ArrayList<>();

}

@Entity
public class Child {

  @Id
  @GeneratedValue
  private int id;

  private int someField;

}

这是一个单向映射,但如果您愿意,您可以将“父”关联添加到孩子。然后你必须添加方法以确保它们是同步的([见这里])4

如果它们不是唯一的并且没有外键,我不确定这是否可行。但在这种情况下,您可以使用@JoinFormula提供 SQL 查询来连接。


推荐阅读