jpa,eclipselink 2.5.1:OneToMany不处理列而不是主键

时间:2014-02-14 15:33:17

标签: jpa eclipselink one-to-many

我有这两个实体:

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关联。 由于我无法更改数据库模型,我该如何使其工作?

亲切的问候 马西莫

2 个答案:

答案 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的翻译,但没有正确的参数:任何想法如何只生成正确的删除语句?

亲切的问候。 马西莫