【问题标题】:jpa, eclips-link 2.5.1: OneToMany not working on columns not primary keyjpa,eclips-link 2.5.1:OneToMany 不能处理非主键的列
【发布时间】:2014-02-14 15:33:16
【问题描述】:

我有这两个实体:

意象

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

亲切的问候 马西莫

【问题讨论】:

  • 您的映射使用可更新 = 假、可插入 = 假的任何原因?从显示的内容来看,这意味着在 JPA 中永远无法触及这种关系,除非某些内容映射到 Mobile 表中使用的外键字段。

标签: jpa eclipselink one-to-many


【解决方案1】:

它在先前版本中起作用的原因是 EclipseLink 不查看映射中的字段,但是随着 JPA 添加派生 Id 支持,EclipseLink 现在验证外键的数量与 ID 字段的数量匹配。

詹姆斯在这里的回答 JPA @JoinColumn issues while joining on non primary key columns 解释说您需要使用descriptorCustomizer 来更改JPA 映射。因此,您要么不映射 JPA 中的字段(将其标记为 @Transient),然后在定制器中添加映射,要么让 JPA 映射使用所有主键字段,然后将定制器中的映射更改为仅使用 USER_ID -> USER_ID 字段。

EclipseLink 定制器如下所示: http://eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_customizer.htm

【讨论】:

  • 好的,我更新了我的模型,使其在 eclipse 链接 2.5 中有效,并按照您的建议使用映射定制器,现在问题出在以下语句中......(在我的回答中描述)。跨度>
  • 这显示了我将调用以添加关系的方法:grepcode.com/file/repo1.maven.org/maven2/… 您需要事先在现有的 getTargetForeignKeyFields() 和 getSourceKeyFields() 集合上调用 clear。
【解决方案2】:

好的,这是我创建的定制器:

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(""));     
    }

正如 Chris 所建议的,这对选择非常有效。 我不得不修改插入调用,因为 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 的翻译,但没有正确的参数:知道如何只生成正确的删除语句吗?

亲切的问候。 马西莫

【讨论】:

  • 这是错误的,可能取自一个为现有映射添加过滤的示例 - 它假定字段设置正确,以便插入、更新和删除工作正常,只需要添加一些过滤用于阅读。它是一个 UnidirectionalOneToManyMapping,需要清除和重置映射使用的外键/目标键字段。
猜你喜欢
  • 1970-01-01
  • 2021-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-12
  • 2011-11-26
相关资源
最近更新 更多