Hibernate单向@OneToMany关联触发外键更新
Hibernate unidirectional @OneToMany association triggers updates of foreign keys
我有以下实体:
@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "TYPE")
public class Type implements Serializable {
private static final long serialVersionUID = 563398089758359222L;
@NotNull
@Column(name = "OBJECT_TYPE")
private String objectType;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TypeNameId")
@SequenceGenerator(name = "TypeNameId", sequenceName = "SQ_TNAME_WL", allocationSize = 1)
private Long id;
@NotNull
@ToString.Include
private String code;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "BOUND_TO_ID", referencedColumnName = "ID")
@JoinColumn(name = "BOUND_TO_CLASS", referencedColumnName = "OBJECT_TYPE")
private Set<Translation> translations;
}
@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "TRANSLATION")
public class Translation implements Serializable {
private static final long serialVersionUID = -4974947078465122824L;
@NotNull
@Column(name = "OBJECT_TYPE")
private String objectType;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TranslationId")
@SequenceGenerator(name = "TranslationId", sequenceName = "SQ_LTRANSLATION_WL", allocationSize = 1)
private Long id;
@Size(max = 4000)
@Column(name = "VALUE")
private String value;
@Size(max = 150)
@Column(name = "LOCALE")
private String locale;
@Size(max = 150)
@Column(name = "BOUND_TO_CLASS")
private String boundToClass;
@Column(name = "BOUND_TO_ID")
private Long boundToId;
}
其他实体也可能在 Translations table 中有它们的翻译,但不包括与 Translation 实体相关的映射。
当创建带有翻译的类型时,Hibernate 想要执行以下 SQL:
Hibernate:插入类型(代码,object_type,id)值(“代码”,“类型”,1)
Hibernate: 插入翻译 (bound_to_class, bound_to_id, locale, object_type, value, id) values (null, null, "en_US", "翻译", "美国代码", 2)
在列 bound_to_id、bound_to_class 和区域设置上存在不可延迟的唯一约束。由于 bound_to_class 和 bound_to_id 在 Hibernate SQL.
中为 null,因此无法在同一语言环境中为不同类型创建翻译
如何更改映射以允许在不使唯一约束可延迟或使用双向关联的情况下创建翻译?
除了建立 bi-directional 关系外:
public class Type {
..
@OneToMany(mappedBy="type", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Translation> translations;
}
..
public class Translation {
..
@ManyToOne
@JoinColumn(name = "BOUND_TO_ID", referencedColumnName = "ID")
@JoinColumn(name = "BOUND_TO_CLASS", referencedColumnName = "OBJECT_TYPE")
Type type;
}
然后将为您设置 fk 值,另一种方法是自己在 Translation 中映射 BOUND_TO_ID 和 BOUND_TO_CLASS,然后自己从任何 Type 实例中提取它们:
public class Translation {
..
@Column(name = "BOUND_TO_CLASS")
private String objectType;
@Column(name = "BOUND_TO_ID")
private Long objectId;
}
然后您需要将类型中的关系标记为 read-only:
public class Type {
..
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "BOUND_TO_ID", referencedColumnName = "ID", updatable=false, insertable=false)
@JoinColumn(name = "BOUND_TO_CLASS", referencedColumnName = "OBJECT_TYPE", updatable=false, insertable=false)
private Set<Translation> translations;
}
由于生成了 Type id,您需要先对 Type 调用 persist,刷新上下文以确保分配了 ID,然后使用 ID 和 objectType 来设置您希望创建的任何 Transaction 实例指向它。
我有以下实体:
@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "TYPE")
public class Type implements Serializable {
private static final long serialVersionUID = 563398089758359222L;
@NotNull
@Column(name = "OBJECT_TYPE")
private String objectType;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TypeNameId")
@SequenceGenerator(name = "TypeNameId", sequenceName = "SQ_TNAME_WL", allocationSize = 1)
private Long id;
@NotNull
@ToString.Include
private String code;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "BOUND_TO_ID", referencedColumnName = "ID")
@JoinColumn(name = "BOUND_TO_CLASS", referencedColumnName = "OBJECT_TYPE")
private Set<Translation> translations;
}
@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "TRANSLATION")
public class Translation implements Serializable {
private static final long serialVersionUID = -4974947078465122824L;
@NotNull
@Column(name = "OBJECT_TYPE")
private String objectType;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "TranslationId")
@SequenceGenerator(name = "TranslationId", sequenceName = "SQ_LTRANSLATION_WL", allocationSize = 1)
private Long id;
@Size(max = 4000)
@Column(name = "VALUE")
private String value;
@Size(max = 150)
@Column(name = "LOCALE")
private String locale;
@Size(max = 150)
@Column(name = "BOUND_TO_CLASS")
private String boundToClass;
@Column(name = "BOUND_TO_ID")
private Long boundToId;
}
其他实体也可能在 Translations table 中有它们的翻译,但不包括与 Translation 实体相关的映射。 当创建带有翻译的类型时,Hibernate 想要执行以下 SQL:
Hibernate:插入类型(代码,object_type,id)值(“代码”,“类型”,1)
Hibernate: 插入翻译 (bound_to_class, bound_to_id, locale, object_type, value, id) values (null, null, "en_US", "翻译", "美国代码", 2)
在列 bound_to_id、bound_to_class 和区域设置上存在不可延迟的唯一约束。由于 bound_to_class 和 bound_to_id 在 Hibernate SQL.
中为 null,因此无法在同一语言环境中为不同类型创建翻译如何更改映射以允许在不使唯一约束可延迟或使用双向关联的情况下创建翻译?
除了建立 bi-directional 关系外:
public class Type {
..
@OneToMany(mappedBy="type", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Translation> translations;
}
..
public class Translation {
..
@ManyToOne
@JoinColumn(name = "BOUND_TO_ID", referencedColumnName = "ID")
@JoinColumn(name = "BOUND_TO_CLASS", referencedColumnName = "OBJECT_TYPE")
Type type;
}
然后将为您设置 fk 值,另一种方法是自己在 Translation 中映射 BOUND_TO_ID 和 BOUND_TO_CLASS,然后自己从任何 Type 实例中提取它们:
public class Translation {
..
@Column(name = "BOUND_TO_CLASS")
private String objectType;
@Column(name = "BOUND_TO_ID")
private Long objectId;
}
然后您需要将类型中的关系标记为 read-only:
public class Type {
..
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "BOUND_TO_ID", referencedColumnName = "ID", updatable=false, insertable=false)
@JoinColumn(name = "BOUND_TO_CLASS", referencedColumnName = "OBJECT_TYPE", updatable=false, insertable=false)
private Set<Translation> translations;
}
由于生成了 Type id,您需要先对 Type 调用 persist,刷新上下文以确保分配了 ID,然后使用 ID 和 objectType 来设置您希望创建的任何 Transaction 实例指向它。