Java JPA一对一插入如何正确使用eclipselink
我试图用JPA和EclipseLink做简单的一对一映射 我在PostgreSQL中有以下DB结构Java JPA一对一插入如何正确使用eclipselink,java,jpa,eclipselink,Java,Jpa,Eclipselink,我试图用JPA和EclipseLink做简单的一对一映射 我在PostgreSQL中有以下DB结构 CREATE TABLE public.employee ( id SERIAL, firstname VARCHAR(20), lastname VARCHAR(20), CONSTRAINT employee_pkey PRIMARY KEY(id) ); CREATE TABLE public.employee_info ( id INTEGER NOT NULL,
CREATE TABLE public.employee (
id SERIAL,
firstname VARCHAR(20),
lastname VARCHAR(20),
CONSTRAINT employee_pkey PRIMARY KEY(id)
);
CREATE TABLE public.employee_info (
id INTEGER NOT NULL,
info TEXT DEFAULT ''::text NOT NULL,
CONSTRAINT employee_info_pkey PRIMARY KEY(id),
CONSTRAINT employee_info_fk FOREIGN KEY (id)
);
我试图用以下代码来反映这一点:
雇员:
@Entity
@Table(name = "employee")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Basic(optional = false)
@Column(name = "firstname")
private String firstname;
@Basic(optional = false)
@Column(name = "lastname")
private String lastname;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "employee")
private EmployeeInfo employeeInfo;
...
}
和员工信息
@Entity
@Table(name = "employee_info")
public class EmployeeInfo implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@Column(name = "info")
private String info;
@OneToOne
@PrimaryKeyJoinColumn
private Employee employee;
...
}
现在我尝试插入数据:
em.getTransaction().begin();
Employee emp = new Employee();
emp.setFirstname("FirstName");
emp.setLastname("LastName");
EmployeeInfo ei = new EmployeeInfo();
ei.setInfo("some info");
emp.setEmployeeInfo(ei);
em.persist(emp);
em.getTransaction().commit();
em.close();
emf.close();
并获取错误,因为JPA生成INSERT查询时没有指定第二个表的id
[EL Info]: 2015-02-28 14:15:31.741--ServerSession(1440332016)--EclipseLink, version: Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd
[EL Info]: connection: 2015-02-28 14:15:31.902--ServerSession(1440332016)--file:/D:/PROJEKTY/JAVA/JPATest3/build/classes/_JPATest3PU login successful
[EL Warning]: 2015-02-28 14:15:31.963--UnitOfWork(2115597658)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: null value in column "id" violates not-null constraint
Detail: Failing row contains (null, some info).
Error Code: 0
Call: INSERT INTO employee_info (info) VALUES (?)
bind => [1 parameter bound]
Query: InsertObjectQuery(jpatest3.EmployeeInfo[ id=null ])
Exception in thread "main" javax.persistence.RollbackException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: null value in column "id" violates not-null constraint
Detail: Failing row contains (null, some info).
Error Code: 0
Call: INSERT INTO employee_info (info) VALUES (?)
bind => [1 parameter bound]
Query: InsertObjectQuery(jpatest3.EmployeeInfo[ id=null ])
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:157)
at jpatest3.JPATest3.main(JPATest3.java:32)
Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: null value in column "id" violates not-null constraint
Detail: Failing row contains (null, some info).
Error Code: 0
Call: INSERT INTO employee_info (info) VALUES (?)
bind => [1 parameter bound]
Query: InsertObjectQuery(jpatest3.EmployeeInfo[ id=null ])
at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.processExceptionForCommError(DatabaseAccessor.java:1611)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:898)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:962)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:631)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:558)
at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:2002)
at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:298)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:242)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:228)
at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.insertObject(DatasourceCallQueryMechanism.java:377)
at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:165)
at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:180)
at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:489)
at org.eclipse.persistence.queries.InsertObjectQuery.executeCommit(InsertObjectQuery.java:80)
at org.eclipse.persistence.queries.InsertObjectQuery.executeCommitWithChangeSet(InsertObjectQuery.java:90)
at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:301)
at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:899)
at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:798)
at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:108)
at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:85)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2896)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1804)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1786)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1737)
at org.eclipse.persistence.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:226)
at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsForClassWithChangeSet(CommitManager.java:193)
at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:138)
at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:4207)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1441)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChangeSet(UnitOfWorkImpl.java:1531)
at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitRootUnitOfWork(RepeatableWriteUnitOfWork.java:277)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1169)
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commit(EntityTransactionImpl.java:132)
... 1 more
Caused by: org.postgresql.util.PSQLException: ERROR: null value in column "id" violates not-null constraint
Detail: Failing row contains (null, some info).
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2157)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1886)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:555)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:417)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:363)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:890)
... 33 more
Java Result: 1
有人能告诉我我做错了什么,以及如何修复代码或数据结构,使其与JPA/Eclipselink一起正常工作吗
多谢各位
编辑1:
下面的代码可以工作,但这是应该的方式吗
Employee emp = new Employee();
emp.setFirstname("FirstName");
emp.setLastname("LastName");
em.persist(emp);
em.flush();
EmployeeInfo ei = new EmployeeInfo(emp.getId(), "some info");
em.persist(ei);
编辑2:
一段时间后,我发现如何实现我想要的。
我问错了问题。这不是一对一的映射。
它就像@SecondaryTable注释一样简单。使用@SecondaryTables注释,一个实体可以分布在两个或多个表中,这就是我想要实现的
@Entity
@Table(name = "employee")
@SecondaryTable(name = "employee_info")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@Column(table = "employee_info")
private String longName;
您映射了由EmployeeInfo管理的关系,这意味着您还必须在新创建的EmployeeInfo对象上设置employee,因为JPA不会为您这样做。现在,JPA尝试在没有父对象的情况下保存employeeinfo,您会得到null键,但这还不是全部 employinfo主键是员工的主键,因此不能在声明@GeneratedValuestrategy=GenerationType.IDENTITY时生成它,但它必须采用其父employee对象的主键 您需要在EmployeeInfo中的@OneToOne映射上使用@Id或@PrimaryKeyJoinColumn来通知JPA密钥应该从父级派生,这里有解释: 最后,如果将employee上的ID生成从Identity更改为Table,效果会更好。这样,JPA在插入之前就知道密钥,可以在两个对象上设置密钥,否则它必须先插入并检索主键集 例如:
EmployeeInfo {
@Id
@Column(name = "id")
...
@OneToOne
@Id
@JoinColumn(name="id", referencedColumnName="id")
private Employee employee;
}
Employee emp = new Employee();
emp.setFirstname("FirstName");
emp.setLastname("LastName");
EmployeeInfo ei = new EmployeeInfo("some info");
ei.setEmploy(emp);
emp.setEmployeeInfo(ei);
em.persist(emp);
谢谢你的回答。事实上,EmployeeInfo中的@GeneratedValuestrategy=GenerationType.IDENTITY是错误的。虽然我解决了这个问题,但仍然有错误。我想继续使用数据库生成的标识。这是否意味着我必须手动刷新员工,然后将其id传递给employeeInfo?对我来说,这打破了整个想法。我遗漏了什么吗?当我手动刷新employee时,我添加了工作正常的代码,但这是正确的方法吗?您阅读了链接吗?将@Id添加到OneToOne映射中,删除生成的值,设置employee on info和info on employee对象。将您已有的员工cascade.all保留在您的父级上。我用一些代码编辑了答案。谢谢你的解释和代码。与此同时,我意识到应该怎么做。所有的问题都源于我网站上的误解。我认为我应该在Employee类中映射EmployeeInfo并坚持emp,而不是ei。但事实恰恰相反。我正在阅读Apress Pro JPA 2手册,现在很多事情都得到了解释,也更加清楚了,这也要感谢您的帮助,我非常感谢您的帮助。我仍然很好奇如何构建一个模型,其中员工数据分布在3 db表中。我认为目前的模式行不通。你能告诉我在那种情况下该怎么办吗?我们将有employee、employeeInfo1、employeeInfo2,所有这些都具有共享主键。
Employee e = new Employee();
e.setName("name");
e.setLongName("long name");
em.getTransaction().begin();
em.persist(e);
em.getTransaction().commit();
emf.close();
EmployeeInfo {
@Id
@Column(name = "id")
...
@OneToOne
@Id
@JoinColumn(name="id", referencedColumnName="id")
private Employee employee;
}
Employee emp = new Employee();
emp.setFirstname("FirstName");
emp.setLastname("LastName");
EmployeeInfo ei = new EmployeeInfo("some info");
ei.setEmploy(emp);
emp.setEmployeeInfo(ei);
em.persist(emp);