我的实体(MyEntity)中有以下字段:
@OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
@JoinColumn(name="ID", referencedColumnName="ID")
@MapKey(name="localeForDB")
private Map<String, MyEntityTranslations> translations;
MyEntityTranslations 看起来像这样:
@Entity
@Table(name="MY_ENTITY_TRANSLATIONS")
public class MyEntityTranslations extends CustomTranslations
{
private String prop1;
private String prop2;
//..getters and setters
}
最后 CustomTranslations 看起来像这样:
@MappedSuperclass
@Access(AccessType.FIELD)
public abstract class CustomTranslations
{
@Id
protected Long id;
@Transient
protected Locale locale;
@Column(name="LOCALE", nullable=false)
@Access(AccessType.PROPERTY)
@Id
protected String getLocaleForDB()
{
return locale.toString();
}
protected void setLocaleForDB(String localeFromDB)
{
//logic for creating a Locale object from a String
}
}
当我从数据库中提取数据时,一切都很好。我得到一个 MyEntity 并且地图已按预期填充。但是,当我尝试插入数据(保存 MyEntity)时,我会出错。这是日志中的内容:
[EL Fine]: 2012-09-04 23:40:19.989--ClientSession(101408113)--Connection(1411623120)--Thread(Thread[http-8080-1,5,main])--select nextval(MY_ENTITY_SEQ_GEN)
[EL Fine]: 2012-09-04 23:40:20.048--ClientSession(101408113)--Connection(1411623120)--Thread(Thread[http-8080-1,5,main])--INSERT INTO MY_ENTITY (ID, STUFF, FOR, MY_ENTITY,) VALUES (?, ?, ?, ?)
bind => [1, foo1, foo2, foo3]
[EL Fine]: 2012-09-04 23:40:20.13--ClientSession(101408113)--Connection(1411623120)--Thread(Thread[http-8080-1,5,main])--INSERT INTO MY_ENTITY_TRANSLATIONS (ID, LOCALE, PROP1, PROP2) VALUES (?, ?, ?, ?)
bind => [null, en_US, My Prop1, My Prop2]
[EL Fine]: 2012-09-04 23:40:20.135--ClientSession(101408113)--Thread(Thread[http-8080-1,5,main])--SELECT 1
[EL Warning]: 2012-09-04 23:40:20.139--UnitOfWork(1394902291)--Thread(Thread[http-8080-1,5,main])--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: org.postgresql.util.PSQLException: ERROR: null value in column "id" violates not-null constraint
Error Code: 0
Call: INSERT INTO MY_ENTITY_TRANSLATIONS (ID, LOCALE, PROP1, PROP2) VALUES (?, ?, ?, ?)
bind => [null, en_US, My Prop1, My Prop2]
Query: InsertObjectQuery(com.foo.MyEntityTranslations@53fd3a3b)
Sep 4, 2012 11:40:54 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet appServlet threw exception
org.postgresql.util.PSQLException: ERROR: null value in column "id" violates not-null constraint
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2103)
现在,在我尝试保存MyEntity
对象之前,我在地图中看到MyEntityTranslations
条目的 id 字段为空。我理解这一点,因为MyEntity
它本身还没有 id。中的 id 字段MyEntity
具有以下注释:
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="MY_ENTITY_SEQ_GEN")
因此,它在插入时从序列中获取其 id。我的问题是我需要如何注释地图以便该 id 也被MyEntityTranslations
记录在案?我在 上尝试了不同的属性@JoinColumn
,但似乎没有任何效果。我是一个 JPA 新手,所以我可能遗漏了一些明显的东西。我想保持所有 JPA 实现独立,但如果重要的话,我使用的是 EclipseLink 2.3.2。
根据以下建议,我将 CustomTranslations 更改为如下所示:
@MappedSuperclass
@Access(AccessType.FIELD)
public abstract class CustomTranslations<T>
{
@Id
@ManyToOne
@JoinColumn(name="ID")
protected T translationsFor;
@Transient
protected Locale locale;
@Column(name="LOCALE", nullable=false)
@Access(AccessType.PROPERTY)
@Id
protected String getLocaleForDB()
{
return locale.toString();
}
protected void setLocaleForDB(String localeFromDB)
{
//logic for creating a Locale object from a String
}
}
然后我的地图MyEntity
看起来像这样:
@OneToMany(mappedBy="translationsFor", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
@MapKey(name="localeForDB")
private Map<String, MyEntityTranslations> translations;
我确定我只是误解了某些东西,但是在尝试保存 MyEntity 实例时,我仍然遇到与以前完全相同的错误。