What's the lazy strategy and how does it work?

I have a problem. I am learning JPA. I am using the built-in OpenEJB container in unit tests, but only works @OneToMany(fetch=EAGER)

. Otherwise, the collection is always null. I haven't found how the lazy strategy works, how does the container populate data, and under what circumstances does the container run to load?

I read that the action is triggered when the receiver is called. But when I have the code:

@OneToMany(fetch = LAZY, mappedBy="someField")
private Set<AnotherEntities> entities = new Set<AnotherEntities>();
...
public Set<AnotherEntities> getEntities() {
    return entities;
}

      

I always get null. I believe the LAZY strategy cannot be tested with an inline container. The problem can also be in a bidirectional relationship.

Does anyone else have similar JPA testing experiments?

Applications

Real test case with setup:

@RunWith(UnitilsJUnit4TestClassRunner.class)
@DataSet("dataSource.xml")
public class UnitilsCheck extends UnitilsJUnit4 {
    private Persister prs;

    public UnitilsCheck() {
        Throwable err = null;
        try {
            Class.forName("org.hsqldb.jdbcDriver").newInstance();
            Properties props = new Properties();
            props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
            props.put("ds", "new://Resource?type=DataSource");
            props.put("ds.JdbcDriver", "org.hsqldb.jdbcDriver");
            props.put("ds.JdbcUrl", "jdbc:hsqldb:mem:PhoneBookDB");
            props.put("ds.UserName", "sa");
            props.put("ds.Password", "");
            props.put("ds.JtaManaged", "true");
            Context context = new InitialContext(props);
            prs = (Persister) context.lookup("PersisterImplRemote");
        }
        catch (Throwable e) {
            e.printStackTrace();
            err = e;
        }
        TestCase.assertNull(err);
    }

    @Test
    public void obtainNickNamesLazily() {
        TestCase.assertNotNull(prs);
        PersistableObject po = prs.findByPrimaryKey("Ferenc");
        TestCase.assertNotNull(po);
        Collection<NickNames> nicks = po.getNickNames();
        TestCase.assertNotNull(nicks);
        TestCase.assertEquals("[Nick name: Kutyafája, belongs to Ferenc]", nicks.toString());
    }
}

      

bean Presister

is a bean that mediates entity beans. The critical class of a class follows:

@PersistenceUnit(unitName="PhonePU")
protected EntityManagerFactory emf;

public PhoneBook findByPrimaryKey(String name) {
    EntityManager em = emf.createEntityManager();

    PhoneBook phonebook = (PhoneBook)em.find(PhoneBook.class, name);
    em.close();

    return phonebook;
}

      

Entity PhoneBook

is one line of the phone book (also person). One person can have zero or more nicknames. With EAGER, the strategy works. With LAZY, the collection is always zero. Maybe the problem is with objects detaching. (See OpenEJB - JPA Concepts , part of Caches and Detach.) But the manual says that the collection can sometimes (more as many times) be empty, but not null.

+2


source to share


2 answers


The problem lies in the lifecycle of the object. (Geronimo uses OpenJPA, so don't read the OpenJPA tutorial, the Object Lifecycle Management part .) The application uses a managed transaction container. Each method call on a bean Persiser

is done in its own transaction. The persistence context depends on the transaction. The entity is disconnected from its context at the end of the transaction, thus at the end of the method. I tried to get the entity and the second line in the same method to get a collection of nicknames and it worked. So the problem has been identified: I cannot get additional entity data from the datastore without re-binding the entity to some persistence context. The object is re-bound by the method EntityManager.merge()

.

The code needs additional fixes. Since the object cannot get a reference EntityManager

and reconnect, the method that returns nicknames must be moved to a class Persister

. (Herek's comment marks the critical line reattaching the object.)

public Collection<NickNames> getNickNamesFor(PhoneBook pb) {
    //emf is an EntityManagerFactory reference
    EntityManager em = emf.createEntityManager();
    PhoneBook pb = em.merge(pb); //Heureka!
    Collection<NickNames> nicks = pb.getNickNames();
    em.close();
    return nicks;
}

      

Then the fee is received in this way:



//I have a PhoneBook instance pb
//pb.getNickNames() returns null only
//I have a Persister instance pe
nicks = pe.getNickNames(pb);

      

What all.

You can see my second question on this topic that I asked on this forum. This is OpenJPA qustion - lazy fetching doesn't work .

+2


source


How will I write the code

@Entity
public class MyEntity {

  @OneToMany(fetch = LAZY, mappedBy="someField")
  private Set<AnotherEntities> entities;

  // Constructor for JPA
  // Fields aren't initalized here so that each em.load
  // won't create unnecessary objects
  private MyEntity() {}

  // Factory method for the rest 
  // Have field initialization with default values here
  public static MyEntity create() {
    MyEntity e = new MyEntity();
    e.entities = new Set<AnotherEntities>();
    return e;
  }

  public Set<AnotherEntities> getEntities() {
    return entities;
  }

}

      

Idea number 2:

I just thought that the order of operations in the EAGER and LAZY selection might be different, that is, the EAGER selection might

  • Declare field entities

  • Sample value for entities

    (I would guess null

    )
  • The set value entities

    isnew Set<T>()

while LAZY may



  • Declare field `entity
  • set value entities

    tonew Set<T>()

  • Sample value for entities

    (I would guess null

    ) '

You need to find a quote for this.

Idea # 1: (Wrong answer)

What if you want to annotate a getter instead of a field? This should instruct JPA to use getters and setters instead of accessing the field.

In the Java Persistence API, an entity can have field or property based access. In field access, a persistence provider accesses the state of an object directly through its instance variables . In property-based access, the continuity provider uses JavaBeans-style get / set accessor methods to access entity persistent properties.

From Java Persistence API - A Simplified Programming Model for Persisting Entities

0


source







All Articles