JPA @ElementCollection 生成奇怪的唯一键
JPA @ElementCollection generates strange unique key
我有一个实体 class PositionOrdering,其中包含一个元素集合:
@ElementCollection(targetClass = Position.class, fetch = FetchType.EAGER)
@CollectionTable(name = "POSITION_ORDERING_POSITION",
joinColumns = @JoinColumn(name = "position_ordering_id"))
@OrderColumn
List<Position> positions = new ArrayList<>();
当hibernate生成数据库结构时,它看起来是这样的:
CREATE TABLE wls.position_ordering_position
(
position_ordering_id bigint NOT NULL,
positions_id bigint NOT NULL,
positions_order integer NOT NULL,
...
}
没关系,完全符合我的预期。 但它还在 positions_id
列上生成一个唯一的约束。 这很奇怪,因为位置 ID 应该只在每次排序时是唯一的,所以以下任何唯一键都可以:
- position_ordering_id + positions_order
- position_ordering_id + positions_id
但不在positions_id的单列上。
因为约束是自动生成的,我不能简单地忽略或删除它。
我能否配置我的集合以创建正确的唯一约束或至少不创建任何约束?
更新:
至于请求,这里是 Position 实体的骨架:
@Entity
@SequenceGenerator(name = EntityBase.SEQUENCE_NAME,
sequenceName = "POSITION_ID_SEQ")
@Table(name = "position")
public class Position extends EntityBase {
// Lots of fields, like row, column number, and type, etc.
}
其中 EntityBase 是一个简单的 class,具有一些实用函数和 Id:
@MappedSuperclass
public abstract class EntityBase implements Serializable, Cloneable {
public static final String SEQUENCE_NAME = "SEQUENCE_GENERATOR";
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = SEQUENCE_NAME)
protected Long id;
//..
}
@ElementCollection
用于映射基本类型或@Embedded
类,不是实体。来自 the documentation
An ElementCollection can be used to define a one-to-many relationship to an Embeddable object, or a Basic value (such as a collection of Strings).
由于 Position
是 @Entity
,您应该将其映射为 @OneToMany
或 @ManyToMany
。我不知道您生成唯一密钥的确切原因,但我想如果您在 a was 中使用注释,则可能会出现不可预测的结果。
正如 Predrag Maric 在接受的答案中所描述的那样,问题在于 Position 不是“可嵌入的”。我的解决方案是:
我创建了一个支持 class,它将 Position 包装到一个 @Embeddable 实体中:
@Embeddable
//@Table(name = "position_ordering_position")
public class PositionOrderingPosition {
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "position_id", nullable = false)
private Position position;
public PositionOrderingPosition() {
}
public PositionOrderingPosition(Position position) {
this.position = position;
}
public Position getPosition() {
return position;
}
}
此外,我将元素集合更改为:
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "POSITION_ORDERING_POSITION",
joinColumns = @JoinColumn(name = "position_ordering_id"))
@OrderColumn
List<PositionOrderingPosition> positions = new ArrayList<>();
现在它创建相同的 table,但具有正确的约束。
我有一个实体 class PositionOrdering,其中包含一个元素集合:
@ElementCollection(targetClass = Position.class, fetch = FetchType.EAGER)
@CollectionTable(name = "POSITION_ORDERING_POSITION",
joinColumns = @JoinColumn(name = "position_ordering_id"))
@OrderColumn
List<Position> positions = new ArrayList<>();
当hibernate生成数据库结构时,它看起来是这样的:
CREATE TABLE wls.position_ordering_position
(
position_ordering_id bigint NOT NULL,
positions_id bigint NOT NULL,
positions_order integer NOT NULL,
...
}
没关系,完全符合我的预期。 但它还在 positions_id
列上生成一个唯一的约束。 这很奇怪,因为位置 ID 应该只在每次排序时是唯一的,所以以下任何唯一键都可以:
- position_ordering_id + positions_order
- position_ordering_id + positions_id
但不在positions_id的单列上。
因为约束是自动生成的,我不能简单地忽略或删除它。
我能否配置我的集合以创建正确的唯一约束或至少不创建任何约束?
更新:
至于请求,这里是 Position 实体的骨架:
@Entity
@SequenceGenerator(name = EntityBase.SEQUENCE_NAME,
sequenceName = "POSITION_ID_SEQ")
@Table(name = "position")
public class Position extends EntityBase {
// Lots of fields, like row, column number, and type, etc.
}
其中 EntityBase 是一个简单的 class,具有一些实用函数和 Id:
@MappedSuperclass
public abstract class EntityBase implements Serializable, Cloneable {
public static final String SEQUENCE_NAME = "SEQUENCE_GENERATOR";
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = SEQUENCE_NAME)
protected Long id;
//..
}
@ElementCollection
用于映射基本类型或@Embedded
类,不是实体。来自 the documentation
An ElementCollection can be used to define a one-to-many relationship to an Embeddable object, or a Basic value (such as a collection of Strings).
由于 Position
是 @Entity
,您应该将其映射为 @OneToMany
或 @ManyToMany
。我不知道您生成唯一密钥的确切原因,但我想如果您在 a was 中使用注释,则可能会出现不可预测的结果。
正如 Predrag Maric 在接受的答案中所描述的那样,问题在于 Position 不是“可嵌入的”。我的解决方案是:
我创建了一个支持 class,它将 Position 包装到一个 @Embeddable 实体中:
@Embeddable
//@Table(name = "position_ordering_position")
public class PositionOrderingPosition {
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "position_id", nullable = false)
private Position position;
public PositionOrderingPosition() {
}
public PositionOrderingPosition(Position position) {
this.position = position;
}
public Position getPosition() {
return position;
}
}
此外,我将元素集合更改为:
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "POSITION_ORDERING_POSITION",
joinColumns = @JoinColumn(name = "position_ordering_id"))
@OrderColumn
List<PositionOrderingPosition> positions = new ArrayList<>();
现在它创建相同的 table,但具有正确的约束。