我有这两个实体:
Anagrafica
@Entity
@Access(AccessType.FIELD)
@Table(name = "S_MC_CC_USER")
@SequenceGenerator(name = "SEQ_ID", sequenceName = "SEQ_ID", allocationSize = 1)
public class Anagrafica implements Serializable{
private static final long serialVersionUID = 332466838544720886L;
@EmbeddedId
private AnagraficaId anagraficaId;
@Column(name = "USER_ID")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ID")
private Long userId;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "USER_ID", updatable = false, insertable = false)
private List<Mobile> mobiles;
/**
* La classe di dominio che modella la chiave primaria di un {@link Anagrafica}
*
* @author Massimo Ugues
*
*/
@Embeddable
static public class AnagraficaId implements Serializable {
private static final long serialVersionUID = -54640203292300521L;
@Column(name = "ANAG_UTENTE")
private String bt;
@Column(name = "COD_ABI")
private String abi;
public AnagraficaId() {
super();
}
移动
@Entity
@Table(name = "S_MOBILE")
@SequenceGenerator(name = "SEQ_MOBILE", sequenceName = "SEQ_MOBILE", allocationSize = 1)
public class Mobile implements Serializable{
private static final long serialVersionUID = 5999493664911497370L;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_MOBILE_DEVICE_REGISTRY")
@Column(name = "ID_MOBILE")
private Long mobileId;
@Column(name = "DEVICE_TOKEN")
private String deviceToken;
@Column(name = "DATA_INSERIMENTO")
@Temporal(TemporalType.TIMESTAMP)
private Calendar dataInserimento = Calendar.getInstance();
使用eclispe-link 2.1.2一切都很好,但是使用eclispe-link 2.5.1我得到了这个例外:
Caused by: javax.persistence.PersistenceException: Exception [EclipseLink-28018] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): org.eclipse.persistence.exceptions.EntityManagerSetupException
Exception Description: Predeployment of PersistenceUnit [persistence-unit] failed.
Internal Exception: Exception [EclipseLink-7220] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The @JoinColumns on the annotated element [field mobiles] from the entity class [class com.intesasanpaolo.domain.entities.sub.Anagrafica] is incomplete. When the source entity class uses a composite primary key, a @JoinColumn must be specified for each join column using the @JoinColumns. Both the name and the referencedColumnName elements must be specified in each such @JoinColumn.
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.createPredeployFailedPersistenceException(EntityManagerSetupImpl.java:1954)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1945)
at org.eclipse.persistence.jpa.PersistenceProvider.createContainerEntityManagerFactory(PersistenceProvider.java:322)
at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:288)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:310)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1571)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1509)
... 40 more
问题是基于非主键的外键的OneToMany关联。 由于我无法更改数据库模型,我该如何使其工作?
亲切的问候 马西莫
答案 0 :(得分:1)
它在先前版本中工作的原因是EclipseLink不查看映射中的字段,但是在JPA添加派生Id支持的情况下,EclipseLink现在验证与ID字段数匹配的外键数。
詹姆斯在这里回答 JPA @JoinColumn issues while joining on non primary key columns 解释说你需要使用descriptorCustomizer来改变JPA映射。因此,您要么不在JPA中映射字段(将其标记为@Transient),然后在自定义程序中添加映射,要么让JPA映射使用所有主键字段,然后将自定义程序中的映射更改为仅使用USER_ID - &gt; USER_ID字段。EclipseLink定制器如下所示: http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_customizer.htm
答案 1 :(得分:0)
好的,这是我创建的定制器:
public void customize(ClassDescriptor descriptor) throws Exception {
// handle the oneToManyMapping to non foreign keys
ManyToManyMapping mapping = (ManyToManyMapping) descriptor.getMappingForAttributeName("mobileDevices");
ExpressionBuilder builder = new ExpressionBuilder();
mapping.setSelectionCriteria(builder.getField("USER_ID").equal(builder.getParameter("USER_ID")));
// handle the insert statement
mapping.setInsertCall(new SQLCall(""));
}
根据克里斯的建议,选择效果很好。 我不得不修改插入调用,因为eclipse-link试图在我没有的映射表上创建和插入语句。 现在的问题是删除:当我尝试从源关联(即Cliente)删除集合时,如此处所述
Cliente.ClienteId id = new Cliente.ClienteId(abi, bt);
Cliente cliente = clienteRepository.findOne(id);
cliente.setMobileDevices(null);
我需要eclipse链接来删除孤儿。 生成的dml如下:
DELETE FROM S_MC_CC_CLIENTI_S_MOBILE_DEVICE_REGISTRY WHERE ((mobileDevices_ID_MOBILE_DEVICE_REGISTRY = 13) AND ((ANAG_UTENTE = '71576493') AND (COD_ABI = '01025')))
由于我没有映射表,我修改了自定义程序,添加了一个setDeleteCall语句:
mapping.setDeleteCall(new SQLCall("DELETE FROM S_MOBILE_DEVICE_REGISTRY WHERE USER_ID = #USER_ID"));
这样eclipse链接生成2 dml:
DELETE FROM S_MOBILE_DEVICE_REGISTRY WHERE USER_ID = NULL
DELETE FROM S_MOBILE_DEVICE_REGISTRY WHERE (ID_MOBILE_DEVICE_REGISTRY = 13)
第一个是我的SQLCall的翻译,但没有正确的参数:任何想法如何只生成正确的删除语句?
亲切的问候。 马西莫