Bidirectional OneToOne association lazy loading support

Project environment:

Spring 3.4.3
Spring Data JPA 1.10.4
Hibernate 5.2.5
JPA2.1

Problem

  • OneToOne properties not lazy loading, although specifying fetch=LAZY
  • OneToOne properties can lazy loading, specifying fetch=LAZY, optional=false, but save new entity error

Define Entity Phone and PhoneDetails, they are have bidirectional OneToOne associations.

    @Entity(name = "Phone")
    public class Phone {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;

        @Column(name = "number")
        private String number;

        @OneToOne(mappedBy = "phone", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
        @PrimaryKeyJoinColumn
        private PhoneDetails details;

        public Phone() {
        }

        public Long getId() {
        return id;
        }

        public String getNumber() {
        return number;
        }

        public PhoneDetails getDetails() {
        return details;
        }

        public void setDetails(PhoneDetails details) {
        this.details = details;
        }

    }
    @Entity
    public class PhoneDetails {

        @Id
        private Long id;

        private String provider;

        private String technology;

        @OneToOne(fetch = FetchType.LAZY)
        @MapsId
        @JoinColumn(name = "id")
        private Phone phone;

        public PhoneDetails() {
        }

        public String getProvider() {
            return provider;
        }

        public String getTechnology() {
            return technology;
        }

        public void setTechnology(String technology) {
            this.technology = technology;
        }

        public Phone getPhone() {
            return phone;
        }

        public void setPhone(Phone phone) {
            this.phone = phone;
        }
    }

Save a new phone with new details:

    Phone phone = new Phone();
    PhoneDetails details = new PhoneDetails();
    phone.setDetails(details);
    details.setPhone(phone);
    phoneDao.save(phone);
  • When setting association specifying “optional=true” (i.e. default value), above codes work OK. But phone’s details property can not lazy loading, although specify “fetch = FetchType.LAZY”. Other associations (e.g. ManyToOne, ManyToMany, OneToMany) lazy load normally.
  • Runing above codes specifying “optional=false” in two entities, will throw exception like following:
org.springframework.orm.jpa.JpaSystemException: null id generated for:class PhoneDetails; nested exception is org.hibernate.id.IdentifierGenerationException: null id generated for:class PhoneDetails

Solution(for me using solution 3):

1.using hibernate bytecode enhance build time

  • toOne(OneToOne, ManyToOne) properties annotation with (no_proxy, lazy,optional=true)
  • no need to change save codes.
  • need to setting build time hibernate enhance plugin
    for maven:
                <build>
                    <plugins>
                    [...]
                    <plugin>
                        <groupId>org.hibernate.orm.tooling</groupId>
                        <artifactId>hibernate-enhance-maven-plugin</artifactId>
                        <version>${hibernateVersion}</version>
                        <executions>
                        <execution>
                            <configuration>
                            <failOnError>true</failOnError>
                            <enableLazyInitialization>true</enableLazyInitialization>
                            <enableDirtyTracking>false</enableDirtyTracking>
                            < >false</enableAssociationManagement>
                            </configuration>
                            <goals>
                            <goal>enhance</goal>
                            </goals>
                        </execution>
                        </executions>
                    </plugin>
                    [...]
                    </plugins>
                </build>

if eclipse reporting error, add settings:

                <pluginManagement>
                    <plugins>
                        [...]
                        <plugin>
                            <groupId>org.eclipse.m2e</groupId>
                            <artifactId>lifecycle-mapping</artifactId>
                            <version>1.0.0</version>
                            <configuration>
                                <lifecycleMappingMetadata>
                                    <pluginExecutions>
                                        <pluginExecution>
                                            <pluginExecutionFilter>
                                                <groupId>org.hibernate.orm.tooling</groupId>
                                                <artifactId>hibernate-enhance-maven-plugin</artifactId>
                                                <versionRange>[1.0.0,)</versionRange>
                                                <goals>
                                                    <goal>enhance</goal>
                                                </goals>
                                            </pluginExecutionFilter>
                                            <action>
                                                <execute />
                                            </action>
                                        </pluginExecution>                          
                                </lifecycleMappingMetadata>
                            </configuration>
                        </plugin>
                        [...]
                    </plugins>
                </pluginManagement>

notice:

  • get one lazy property will trigger all lazy properties loading, because they are in one lazy group.
  • ManyToMany propertis possiblly not loading(v5.25), save the entity caused to lose the association.
  • enableDirtyTracking and enableAssociationManagement existing some issues in version 5.25?

2.using jpa bytecode enhance run time

reference hibernate document, in my test, not success.

3.split two steps for saving entity:

  • save parent entity(phone) first,
  • save child entity(phoneDetails) secondly.
            Phone phone = new Phone();
            PhoneDetails details = new PhoneDetails();
            phoneDao.save(phone);
            phone.setDetails(details);
            details.setPhone(phone);
            detailDao.save(details);    

above codes work normally.

Conclution

From my test, hibernate bytecode enhance build time and runing time possiblly have certain issues, run time more servere, please care to use. Futhermore, bytecode enhance must add Hibernate Annotations in your domain entities, not JPA specification. Good news is we can avoid to use bytecode enhance, like solution 3, meanwhile eliminate Hibernate Annations and enhance plugin setting.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值