13

I am trying examples for fetchType.Lazy, however while debugging the code, it seems that fetchType.Lazy is not working.

Entity bean: Address

Added annotation @Basic with property fetch=fetchType.Lazy on district field.

My entity bean is defined by the code below:

    package model;

    import java.io.Serializable;
    import javax.persistence.*;
    import java.util.List;


    /**
     * The persistent class for the address database table.
     */
    @Entity
    @Table(name="address", schema="home")
    public class Address implements Serializable {
        private static final long serialVersionUID = 1L;

        @TableGenerator(name = "addr_gen", table = "table_generator", pkColumnName = "gen_name", valueColumnName = "gen_val", allocationSize=1)
        @Id
        @GeneratedValue(strategy=GenerationType.TABLE, generator="addr_gen")
        private String addressId;

        private String city;

        @Basic(fetch=FetchType.LAZY)
        @Column(name="district")
        private String district;

        private String houseNumber;

        private String pincode;

        private String state;

        private String street;

        //bi-directional many-to-one association to Employee
        @OneToMany(mappedBy="address")
        private List<Employee> employees;

        public Address() {
        }


        public String getAddressId() {
            return this.addressId;
        }

        public void setAddressId(String addressId) {
            this.addressId = addressId;
        }

        public String getCity() {
            return this.city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public String getDistrict() {
            return this.district;
        }

        public void setDistrict(String district) {
            this.district = district;
        }

        public String getHouseNumber() {
            return this.houseNumber;
        }

        public void setHouseNumber(String houseNumber) {
            this.houseNumber = houseNumber;
        }

        public String getPincode() {
            return this.pincode;
        }

        public void setPincode(String pincode) {
            this.pincode = pincode;
        }

        public String getState() {
            return this.state;
        }

        public void setState(String state) {
            this.state = state;
        }

        public String getStreet() {
            return this.street;
        }

        public void setStreet(String street) {
            this.street = street;
        }

        public List<Employee> getEmployees() {
            return this.employees;
        }

        public void setEmployees(List<Employee> employees) {
            this.employees = employees;
        }


        public Employee addEmployees(Employee employees) {
            getEmployees().add(employees);
            employees.setAddress(this);

            return employees;
        }

        public Employee removeEmployees(Employee employees) {
            getEmployees().remove(employees);
            employees.setAddress(null);

            return employees;
        }

        /*@Override
        public String toString() {
            return "Address [addressId=" + addressId + ", city=" + city
                    + ", district=" + district + ", houseNumber=" + houseNumber
                    + ", pincode=" + pincode + ", state=" + state + ", street="
                    + street + ", employees=" + employees + "]";
        }*/
    }

The method which uses above entity bean:

public Address findAddress(EntityManagerFactory emf, UserTransaction tx) {
    EntityManager em = emf.createEntityManager();
    Address addr = null;
    try {
        tx.begin();
        addr = em.find(Address.class, new String("154"));
        tx.commit();
    } catch (Exception e) {
        e.printStackTrace();
    }

    return addr;
}

So after the find method call, when I inspected the address object, it was already populated with district field.

Please let me know whether I am missing some configuration or whether there is some issue with the code itself.

gandreadis
  • 3,004
  • 2
  • 26
  • 38
Shashi Shankar
  • 859
  • 2
  • 8
  • 25

3 Answers3

13

The problem is that when using in the @Basic annotation the application server can/may decide on his own, when it is better to fetch the data. As documented here

The EAGER strategy is a requirement on the persistence provider runtime that the value must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime.

@OneToMany-like annotations have according to the documentation the same problem, but in that case it much more likely that the JPA provider will consider the FetchType hint.

On the other hand, you could try with a big data field, like

@Lob
@Basic(fetch=FetchType.LAZY)
private byte[] document;

to see whether something changes (although again, your application server can decide to fetch always the field).

In order to check whether a collection field was loaded I would either check the database query logs or do the following:

@PersistenceContext private EntityManager em;
.....
Person person = em.find(Person.class, 1L);//Person entity has a OneToMany relationship to entity Address
em.detach(person);
person.getAddresses().size();//if the Address are now not fetched, it the call should  throw an error
V G
  • 18,822
  • 6
  • 51
  • 89
  • Thanks Andrei for the response, I will check and update the same. In addition to this I tried with @ManytoOne relationship also but fetchType.Lazy didn't worked. – Shashi Shankar Sep 09 '13 at 11:46
  • I meant @OneToMany. Try this in the imaginary Person entity: @OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.ALL}) private Set
    addresses; and check in the database logs what queries are executed when you just execute EntityManager.find(Person.class, 1). How do you check whether the field is populated? (checking it with person.getAddressed() is not meaningful)
    – V G Sep 09 '13 at 12:12
  • The same code which I posted in question is working fine now... :-) – Shashi Shankar Sep 09 '13 at 17:16
  • I am using debugger to check whether fields are populated or not. After calling find method I am inspecting the object and there after call of getter. – Shashi Shankar Sep 09 '13 at 17:22
  • 1
    @ShashiShankar please mention what you have done so that the code started working – Dhruv Raj Singh Aug 25 '16 at 18:34
0

Ensure you have weaving enabled.

http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving

James
  • 17,965
  • 11
  • 91
  • 146
-1

To initialize laze in JPA, you need to invoke a jar library and start it, if it is with maven or manual por example , if you need laze, use jar in maven jar de.empulse.eclipselink More info http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving/Static_Weaving#Use_the_Maven_plugin

If you don use maven , you can making manually enabled the jar

GuapoSasa
  • 27
  • 2