我有一个很难用 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;
}
@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;
}
@Entity
public class Sub1Entity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String otherProperties;
}
@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;
}
@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
它属于。我很确定一旦我解决了这个问题就会出现更多问题,希望有人会告诉我这个模型最终是否会奏效。
当你有一个像这样的圆形模型并将两侧指定为单向时,你已经双重/三次映射了一些 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。