Hibernate 将祖父映射到孩子

问题描述 投票:0回答:1

我有一个很难用 Hibernate 注释表示的模型。我已经尝试了很多东西,但我最大的问题是我无法将祖父 ID 放入子实体以仅将相关记录带入数据库。

这是模特:

这个模型的想法是,一切都可以在多个

Main
实体中重用。

Main
可以包含一个
Sub1
元素的列表,这些元素没有分配给其他任何东西,但是那些
Sub1
实体也可以在
Sub2
内部。同样的事情发生在
Sub2
上,它们可以直接分配给
Main
但也可以在
Sub3
中。

Sub1
有一个特定的顺序,以后只能为那个特定的
Main
重新排序,所以
Sub1_Ordering
实体是在逻辑中生成的,并在 Hibernate 之外分配了一个顺序。

由于

Sub2
Sub3
可以在多个
Main
中重复使用,映射是在连接表中完成的,它们内部没有属性告诉您它属于哪里,连接表提供了该信息。
Sub1
也可以添加到其他实体内部或外部的多个
Mains
,但顺序不同。

这是我的实体到目前为止的样子,为简单起见删除了一些不相关的部分:

主要
@Entity
public class MainEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @OneToMany(cascade = CascadeType.MERGE, mappedBy = "main")
  @Where(clause = "sub2_id is null")
  private Set<Sub1OrderingEntity> sub1ordering = new HashSet<>();

  @OneToMany(cascade = CascadeType.ALL)
  @JoinTable(
      name = "sub2_mapping",
      joinColumns = @JoinColumn(name = "main_id"),
      inverseJoinColumns = @JoinColumn(name = "sub2_id")
  )
  private Set<Sub2Entity> sub2 = new HashSet<>();

  @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH })
  @JoinTable(
      name = "sub3_mapping",
      joinColumns = @JoinColumn(name = "main_id"),
      inverseJoinColumns = @JoinColumn(name = "sub3_id")
  )
  private Set<Sub3Entity> sub3 = new HashSet<>();

  private String otherProperties;

}
Sub1_Ordering
@Entity
public class Sub1OrderingEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @ManyToOne
  @JoinColumn(name = "main_id")
  private MainEntity main;

  @ManyToOne
  @JoinColumn(name = "sub2_id")
  private Sub2Entity sub2;

  @Column(name = "sub1_order")
  private long order;

  @OneToOne(cascade = {CascadeType.ALL})
  @JoinColumn(name = "sub1_id")
  private Sub1Entity sub1;

}
Sub1
@Entity
public class Sub1Entity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String otherProperties;

}
Sub2
@Entity
public class Sub2Entity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @OneToMany(cascade = {CascadeType.ALL})
  @JoinColumns({
      @JoinColumn(name = "sub2_id", referencedColumnName = "id"),
      @JoinColumn(name = "main_id", referencedColumnName = "main_id")
  })
  private Set<Sub1OrderingEntity> sub1ordering = new HashSet<>();

  private String otherProperties;

}
Sub3
@Entity
public class Sub3Entity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @ManyToMany(cascade = CascadeType.ALL)
  @JoinTable(
      name = "sub2_mapping",
      joinColumns = @JoinColumn(name = "sub3_id"),
      inverseJoinColumns = @JoinColumn(name = "sub2_id")
  )
  private Set<Sub2Entity> sub2 = new HashSet<>();

  private String otherProperties;

}

我现在最大的问题是,从

Sub2
开始,我无法分辨哪个是
main_id
,它试图获取它的记录,而是将所有记录分配给
Sub2
,无论哪个
 Main
它属于。我很确定一旦我解决了这个问题就会出现更多问题,希望有人会告诉我这个模型最终是否会奏效。

hibernate jpa spring-data-jpa hibernate-mapping
1个回答
0
投票

当你有一个像这样的圆形模型并将两侧指定为单向时,你已经双重/三次映射了一些 FK 列。即:

子2:

  @OneToMany(cascade = {CascadeType.ALL})
  @JoinColumns({
      @JoinColumn(name = "sub2_id", referencedColumnName = "id"),
      @JoinColumn(name = "main_id", referencedColumnName = "main_id")
  })
  private Set<Sub1OrderingEntity> sub1ordering = new HashSet<>();

Sub1OrderingEntity:

  @ManyToOne
  @JoinColumn(name = "main_id")
  private MainEntity main;

  @ManyToOne
  @JoinColumn(name = "sub2_id")
  private Sub2Entity sub2;

Sub2 中的映射将尝试控制 main_id 和 sub2_id 列,但它们已经通过 Sub1OrderingEntity 的 sub2 和 main 引用设置和控制。另一个问题是您在 Sub2Entity 的表中有一个“main_id”列作为主表中“main_id”列的外键 - 但没有定义这样的列。 Main 表中的列将是基于 id 属性的“id”。

这应该只是:

@Entity
public class Sub2Entity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @OneToMany(mappedBy = "sub2", cascade = {CascadeType.ALL})
  private Set<Sub1OrderingEntity> sub1ordering = new HashSet<>();

  @ManyToOne
  @JoinColumn(name = "main_id")
  private MainEntity main;

  private String otherProperties;
}

请注意,我还从 Sub2Entity->Main 添加了一个引用来控制 main_id 列,它遵循您为 Sub1OrderingEntity 设置的相同模式。由拥有实体设置外键引用通常是一个更好的主意,特别是如果您要对其施加非空约束,以便在插入 Sub2Entity 时可以找到并确定它:允许 JPA 提供程序先插入然后在单独的语句中更新外部控制的映射,因此除非需要,否则最好不要依赖它。

Main 看起来像:

@Entity
public class MainEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @OneToMany(cascade = CascadeType.MERGE, mappedBy = "main")
  @Where(clause = "sub2_id is null")
  private Set<Sub1OrderingEntity> sub1ordering = new HashSet<>();

  @OneToMany(mappedBy = "main", cascade = CascadeType.ALL)
  private Set<Sub2Entity> sub2 = new HashSet<>();

  @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH })
  @JoinTable(
      name = "sub3_mapping",
      joinColumns = @JoinColumn(name = "main_id"),
      inverseJoinColumns = @JoinColumn(name = "sub3_id")
  )
  private Set<Sub3Entity> sub3 = new HashSet<>();

  private String otherProperties;

}

Sub3 然后将与您的发布保持不变,将 sub2_mapping 保持为 Sub3 和 Sub2 之间的关系 ManyToMany 表,只有 sub3_id 和 sub2_id fk 列。如果 Sub3 只是为了引用 Sub2 实例以引用它(这可能是该 sub2_mapping 表的初衷),那么这些与“main”的连接如何工作和维护引用将取决于您的应用程序。

如果是这样,让它工作并发布另一个问题,因为还有许多其他方法可以映射 sub2_mapping。

© www.soinside.com 2019 - 2024. All rights reserved.