Java 作为复合主键一部分的外键和OpenJPA中的多通关系
我想用OpenJPA2.3创建简单的数据库Java 作为复合主键一部分的外键和OpenJPA中的多通关系,java,hibernate,jpa,orm,openjpa,Java,Hibernate,Jpa,Orm,Openjpa,我想用OpenJPA2.3创建简单的数据库 TableA: - f_id PK - item PK - release PK - b_id PK - field1 - field2 TableB: - id PK - name - date 其中TableA中的b_id引用了TableB中的id(多个TableA行到一个TableB行)b_id是整个复合主键的一部分 表格A类: @Entity @IdClass(TableA_PK.class) public c
TableA:
- f_id PK
- item PK
- release PK
- b_id PK
- field1
- field2
TableB:
- id PK
- name
- date
其中TableA
中的b_id
引用了TableB
中的id
(多个TableA
行到一个TableB
行)b_id
是整个复合主键的一部分
表格A类:
@Entity
@IdClass(TableA_PK.class)
public class TableA implements Serializable {
@Id
private int fId;
@Id
private String item;
@Id
private String release;
@Id
@ManyToOne
@PrimaryKeyJoinColumn(name="b_id", referencedColumnName="id")
private TableB tableB;
@Column
private String field1;
@Column
private String field2;
public TableA() {}
//getters, setters, equals, hashCode methods
}
public class TableA_PK implements Serializable {
private int fId;
private String item;
private String release;
private TableB tableB;
public TableA_PK() {}
//getters, setters, equals, hashCode methods
}
@Entity
public class TableB implements Serializable {
@Id
@GeneratedValue
private long id;
@Column
private String name;
@Column
private Date date;
@OneToMany(mappedBy="tableB", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
private List<TableA> rows;
public TableB() {}
//getters, setters, equals, hashCode methods
}
表A主键类:
@Entity
@IdClass(TableA_PK.class)
public class TableA implements Serializable {
@Id
private int fId;
@Id
private String item;
@Id
private String release;
@Id
@ManyToOne
@PrimaryKeyJoinColumn(name="b_id", referencedColumnName="id")
private TableB tableB;
@Column
private String field1;
@Column
private String field2;
public TableA() {}
//getters, setters, equals, hashCode methods
}
public class TableA_PK implements Serializable {
private int fId;
private String item;
private String release;
private TableB tableB;
public TableA_PK() {}
//getters, setters, equals, hashCode methods
}
@Entity
public class TableB implements Serializable {
@Id
@GeneratedValue
private long id;
@Column
private String name;
@Column
private Date date;
@OneToMany(mappedBy="tableB", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
private List<TableA> rows;
public TableB() {}
//getters, setters, equals, hashCode methods
}
表格B类别:
@Entity
@IdClass(TableA_PK.class)
public class TableA implements Serializable {
@Id
private int fId;
@Id
private String item;
@Id
private String release;
@Id
@ManyToOne
@PrimaryKeyJoinColumn(name="b_id", referencedColumnName="id")
private TableB tableB;
@Column
private String field1;
@Column
private String field2;
public TableA() {}
//getters, setters, equals, hashCode methods
}
public class TableA_PK implements Serializable {
private int fId;
private String item;
private String release;
private TableB tableB;
public TableA_PK() {}
//getters, setters, equals, hashCode methods
}
@Entity
public class TableB implements Serializable {
@Id
@GeneratedValue
private long id;
@Column
private String name;
@Column
private Date date;
@OneToMany(mappedBy="tableB", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
private List<TableA> rows;
public TableB() {}
//getters, setters, equals, hashCode methods
}
如何解决这个问题
我的理论/解释:看起来,当我试图持久化TableB
对象时,行的每个元素都必须持久化。但是在TableA
中有一个字段private TableB TableB
(它还没有持久化),所以我们陷入无限递归;)
编辑:
@Entity
@IdClass(TableA_PK.class)
public class TableA implements Serializable {
@Id
private int fId;
@Id
private String item;
@Id
private String release;
@Id
@ManyToOne
@PrimaryKeyJoinColumn(name="b_id", referencedColumnName="id")
private TableB tableB;
@Column
private String field1;
@Column
private String field2;
public TableA() {}
//getters, setters, equals, hashCode methods
}
public class TableA_PK implements Serializable {
private int fId;
private String item;
private String release;
private TableB tableB;
public TableA_PK() {}
//getters, setters, equals, hashCode methods
}
@Entity
public class TableB implements Serializable {
@Id
@GeneratedValue
private long id;
@Column
private String name;
@Column
private Date date;
@OneToMany(mappedBy="tableB", fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
private List<TableA> rows;
public TableB() {}
//getters, setters, equals, hashCode methods
}
完整跟踪(更改前):
更改后的完整跟踪(当我更改table a_PK
中table b
的Long
类型,以及table b
中id
的Long
类型时):
我有例外:
org.apache.openjpa.persistence.RollbackException: The transaction has been rolled back. See the nested exceptions for details on the errors that occurred.
(...)
Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: ERROR: null value in column "b_id" violates not-null constraint
为什么??我认为它将首先保持tb
,然后行中的每个元素都将知道获得的TableB.id(感谢TableA
类中的TableB
字段)。这个怎么了
如果在持久化之前在测试中添加两行:
ta1.setTableB(tb);
ta2.setTableB(tb);
将抛出此异常:
Caused by: java.lang.ClassCastException: org.model.TableB cannot be cast to java.lang.Number
(我需要自己在TableA
中设置tableB
字段吗?)
如何持久化TableB
对象
编辑3:persistence.xml
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="rd-jpa" transaction-type="RESOURCE_LOCAL">
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<class>org.model.TableA</class>
<class>org.model.TableB</class>
<properties>
<property name="openjpa.ConnectionURL"
value="jdbc:postgresql://localhost:5432/mydb" />
<property name="openjpa.ConnectionDriverName" value="org.postgresql.Driver" />
<property name="openjpa.ConnectionUserName" value="postgres" />
<property name="openjpa.ConnectionPassword" value="postgres" />
<property name="openjpa.DynamicEnhancementAgent" value="true" />
<property name="openjpa.RuntimeUnenhancedClasses" value="supported" />
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)" />
</properties>
</persistence-unit>
</persistence>
org.apache.openjpa.persistence.PersistenceProviderImpl
org.model.TableA
org.model.TableB
这对我来说适用于以下代码。更改了TableA_PK中的长tableB和TableA中的@join列
表
@Entity
@IdClass(TableA_PK.class)
public class TableA implements Serializable {
@Id
private int fId;
@Id
private String item;
@Id
private String release;
@Id
@ManyToOne
@JoinColumn(name="b_id")
private TableB tableB;
@Column
private String field1;
@Column
private String field2;
表a_PK
public class TableA_PK implements Serializable {
private int fId;
private String item;
private String release;
private long tableB;
public TableA_PK() {}
//getters, setters, equals, hashCode methods
表B
@Entity
public class TableB implements Serializable {
@Id
@GeneratedValue
private long id;
@Column
private String name;
@Column
private Date date;
@OneToMany(mappedBy="tableB")
private List<TableA> rows;
public TableB() {}
//getters, setters, equals, hashCode methods
@实体
公共类TableB实现了可序列化{
@身份证
@生成值
私人长id;
@纵队
私有字符串名称;
@纵队
私人日期;
@OneToMany(mappedBy=“表B”)
私有列表行;
公共表B(){}
//getter、setter、equals、hashCode方法
评论后更新
不幸的是,派生键不支持生成的值,并且在插入项之前不知道该值。因此,您需要先持久化tableB项,然后添加行。
检查以下代码:
TableB tableb = new TableB();
tableb.setDate(new Date());
tableb.setName("tableb2");
em.persist(tableb); // fills tableb id
System.out.println(tableb);
TableA tableA = new TableA();
tableA.setfId((int) new Date().getTime());
tableA.setField1("field1");
tableA.setField2("field2");
tableA.setItem("item2");
tableA.setRelease("1");
tableA.setTableB(tableb);
ArrayList<TableA> rows = new ArrayList<TableA>();
rows.add(tableA);
tableb.setRows(rows);
em.merge(tableb); // inserts tablea objects, you could also just persist tableA items
TableB TableB=新TableB();
表B.设置日期(新日期());
表B.集合名称(“表B2”);
em.persist(tableb);//填充tableb id
系统输出打印项次(表B);
TableA TableA=新TableA();
tableA.setfId((int)new Date().getTime());
表A.设置字段1(“字段1”);
表A.设置字段2(“字段2”);
表A.设定项目(“项目2”);
表A.设定释放(“1”);
表A.设置表B(表B);
ArrayList行=新的ArrayList();
行。添加(表a);
表B.设置行(行);
em.merge(tableb);//插入tablea对象,也可以只保留tablea项
我相信在TableA_PK中,而不是“TableB TableB”,你只需要TableB中的一个主键,而不是整个实体-“private long TableB;”我明天在工作时会检查这个:)你能告诉我这到底应该是什么样子吗?在TableA_PK中
我需要将private TableB TableB
更改为private long id
>就这样?关于TableA
?不需要更改吗?检查JPA2.0规范中的2.4.1.3派生标识示例。key类中的属性应该与@Id中使用的属性名称匹配,因此它是tableB而不是Id,并且type应该与tableB的主键类型匹配,在您的情况下,这就是为什么我建议使用private-long tableB
。如果它不起作用,我们将寻找其他东西;-)。现在没有时间测试它。TableA中没有变化。它不起作用,@Gas。我添加了完整的异常痕迹,谢谢。但我可能正在“填充”TableA
和TableB
的字段以错误的方式显示对象。请查看我的第二篇postscript,谢谢您的帮助,但它不起作用。我创建实体类和测试类与上述完全相同,我仍然有原因:java.lang.ClassCastException:org.model.TableB无法转换为java.lang.Number
。我添加了mypersistence.xml
文件。我正在考虑重新组织我的数据库架构。这一问题的完整堆栈跟踪是什么:由:java.lang.ClassCastException引起的?为了可读性,我添加了一个新问题:所有源代码