Java 插入具有复合EmbeddedId(包含另一个EmbeddedId的EmbeddedId)的JPA实体的顺序
我正在从事WebSphere8.5.5(OpenJPA2.2.3)中的一个项目,该项目需要通过一个大型JPA注释实体模型进行级联创建和合并。当通过在父级上调用EntityManager.merge()或在提交事务时触发刷新来合并子级时,我们遇到了一个非常特殊的问题。详情如下: 实体映射的相关部分:Java 插入具有复合EmbeddedId(包含另一个EmbeddedId的EmbeddedId)的JPA实体的顺序,java,jpa,jakarta-ee,openjpa,websphere-8,Java,Jpa,Jakarta Ee,Openjpa,Websphere 8,我正在从事WebSphere8.5.5(OpenJPA2.2.3)中的一个项目,该项目需要通过一个大型JPA注释实体模型进行级联创建和合并。当通过在父级上调用EntityManager.merge()或在提交事务时触发刷新来合并子级时,我们遇到了一个非常特殊的问题。详情如下: 实体映射的相关部分: EntityA有一个到EntityB的单间 EntityB有一个到EntityC的oneToMany EntityC有一个到EntityD的oneToMany 它们都有双向映射。实体A和B具有单列主键
@Entity
@Table(name="TableA")
public class EntityA extends BaseEntity {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="TABLE_A_ID_GEN")
@SequenceGenerator(name="TABLE_A_ID_GEN", sequenceName="TABLE_A_ID", allocationSize=1)
@Column(name="TABLE_A_ID")
private Integer id;
@OneToMany(fetch=FetchType.LAZY, mappedBy="entityA", cascade=CascadeType.ALL)
private List<EntityB> entityBList;
...
}
@Entity
@Table(name="TableB")
public class EntityB extends BaseEntity {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="TABLE_B_ID_GEN")
@SequenceGenerator(name="TABLE_B_ID_GEN", sequenceName="TABLE_B_ID", allocationSize=1)
@Column(name="TABLE_B_ID")
private Integer id;
@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
@JoinColumn(name="TABLE_A_ID")
private EntityA entityA;
@OneToMany(fetch=FetchType.LAZY, mappedBy="entityB", cascade=CascadeType.ALL)
private List<EntityC> entityCList;
...
}
@Entity
@Table(name="TableC")
public class EntityC extends BaseEntity {
@EmbeddedId
private EntityC_PK id = new EntityC_PK();
@MapsId("entityB_Id")
@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
@JoinColumn(name="TABLE_B_ID")
private EntityB entityB;
@OneToMany(fetch=FetchType.LAZY, mappedBy="entityC", cascade=CascadeType.ALL)
private List<EntityD> entityDList;
...
}
@Embeddable
public class EntityC_PK implements BaseComponent {
@Column(name="TABLE_B_ID", nullable = false, updatable = false)
private Integer entityB_Id;
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="TABLE_C_ID_GEN")
@SequenceGenerator(name="TABLE_C_ID_GEN", sequenceName="TABLE_C_ID", allocationSize=1)
@Column(name="TABLE_C_ID")
private Integer entityC_Id;
...
}
@Entity
@Table(name="TABLE_D")
public class EntityD extends BaseEntity {
@EmbeddedId
private EntityD_PK id = new EntityD_PK();
@MapsId("entityC_Id")
@JoinColumns({
@JoinColumn(name = "TABLE_B_ID"),
@JoinColumn(name = "TABLE_C_ID")})
@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
private EntityC entityC;
...
}
@Embeddable
public class EntityD_PK implements BaseComponent {
@Embedded
private EntityC_PK entityC_Id;
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="TABLE_D_ID_GEN")
@SequenceGenerator(name="TABLE_D_ID_GEN", sequenceName="TABLE_D_ID", allocationSize=1)
@Column(name="TABLE_D_ID")
private Integer entity_id;
...
}
@实体
@表(name=“TableA”)
公共类EntityA扩展了BaseEntity{
@身份证
@GeneratedValue(策略=GenerationType.SEQUENCE,generator=“表A\U ID\U GEN”)
@SequenceGenerator(name=“TABLE\u A\u ID\u GEN”,sequenceName=“TABLE\u A\u ID”,allocationSize=1)
@列(name=“TABLE\u A\u ID”)
私有整数id;
@OneToMany(fetch=FetchType.LAZY,mappedBy=“entityA”,cascade=CascadeType.ALL)
私有列表实体列表;
...
}
@实体
@表(name=“TableB”)
公共类EntityB扩展了BaseEntity{
@身份证
@GeneratedValue(策略=GenerationType.SEQUENCE,generator=“TABLE_B_ID_GEN”)
@SequenceGenerator(name=“TABLE\u B\u ID\u GEN”,sequenceName=“TABLE\u B\u ID”,allocationSize=1)
@列(name=“TABLE_B_ID”)
私有整数id;
@manytone(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
@JoinColumn(name=“TABLE\u A\u ID”)
私人实体a实体a;
@OneToMany(fetch=FetchType.LAZY,mappedBy=“entityB”,cascade=CascadeType.ALL)
私有列表实体列表;
...
}
@实体
@表(name=“TableC”)
公共类EntityC扩展了BaseEntity{
@嵌入ID
私有EntityC_PK id=新EntityC_PK();
@MapsId(“实体Id”)
@manytone(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
@JoinColumn(name=“TABLE_B_ID”)
私人实体b实体b;
@OneToMany(fetch=FetchType.LAZY,mappedBy=“entityC”,cascade=CascadeType.ALL)
私有列表实体列表;
...
}
@可嵌入
公共类EntityC_PK实现BaseComponent{
@列(name=“TABLE_B_ID”,null=false,updateable=false)
私有整数实体b_Id;
@GeneratedValue(策略=GenerationType.SEQUENCE,generator=“TABLE\u C\u ID\u GEN”)
@SequenceGenerator(name=“TABLE\u C\u ID\u GEN”,sequenceName=“TABLE\u C\u ID”,allocationSize=1)
@列(name=“TABLE_C_ID”)
私有整数实体Id;
...
}
@实体
@表(name=“Table_D”)
公共类EntityD扩展了BaseEntity{
@嵌入ID
private EntityD_PK id=new EntityD_PK();
@MapsId(“实体Id”)
@连接柱({
@JoinColumn(name=“TABLE_B_ID”),
@JoinColumn(name=“TABLE_C_ID”)})
@manytone(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
私人实体实体;
...
}
@可嵌入
公共类EntityD_PK实现BaseComponent{
@嵌入
私有实体PK实体Id;
@GeneratedValue(策略=GenerationType.SEQUENCE,generator=“TABLE\u D\u ID\u GEN”)
@SequenceGenerator(name=“TABLE\u D\u ID\u GEN”,sequenceName=“TABLE\u D\u ID”,allocationSize=1)
@列(name=“TABLE\u D\u ID”)
私有整数实体_id;
...
}
工作原理:
您可以对实体A(附加所有子实体)调用EntityManager.persist(),模型将正确级联persist
什么不起作用:
如果实例化实体A并调用EntityManager.persist(entityA),然后在EntityManager.merge(entityA)(或在提交事务时允许隐式合并)时添加子项、子项等,它将无法以正确的顺序执行INSERT语句。为了使事情更加混乱,插入的顺序在单元测试的重复执行中是不一致的。它尝试在实体C之前插入实体D失败
问题是:
如何在合并时更正JPA注释以强制执行正确的插入顺序(以及更新/删除)
编辑1:
插入/删除顺序非常关键,因为数据库强制执行带有约束的外键关系。首先让我声明(也许我说的是显而易见的,对不起),您应该针对您的场景查看JPA规范……。嵌入式有时有不同的规则。接下来,您声明了“EntityManager.create()”,但我认为您的意思是.persist?你后来谈到合并,所以你是说,合并?不管是哪种方式,我都建议您坚持使用.persist,如果您希望持久化新实体而不是合并。虽然合并不是非法的,但合并通常用于合并分离的实体等
有了这些,让我进入你问题的核心,给你一个可能有助于你的订单的财产。您没有在文本中声明ddl是否包含外键约束。既然你关心秩序,我就认为你有这样的限制。如果您这样做,OpenJPA对这个约束一无所知,因此也不知道如何正确地排序。默认情况下,您不能依赖SQL的顺序,而顺序的随机性正是我所期望的。然而,如果您需要以支持FK约束的方式对事物进行排序,那么您需要允许OpenJPA“了解”您的约束。为此,需要在persistence.xml文件中设置此属性(或者可以将其设置为JVM自定义属性):
此属性允许OpenJPA检查您的模式,这样做可以了解您的FK约束。有了这些知识,OpenJPA可以正确地排序SQL
最后,如果没有FK约束,但希望以某种方式对SQL排序,则可能需要使用以下命令:
<property name="openjpa.jdbc.UpdateManager" value="operation-order"/>
<property name="openjpa.jdbc.UpdateManager" value="operation-order"/>