4. Lazy Initialization

Lazy Initialization (Generalities)

When using object/relational persistence tools like Hibernate or TopLink, you may face the risk of loading your entire database if you are not using any lazy fetching strategy. There are two types of lazy associations between persistent beans: proxy (single-valued associations) and collections (such as List, Set, Bag and Map).

Granite Data Services, via its HibernateExternalizer or TopLinkExternalizer, supports both kinds of lazy associations.

Single-Valued Associations (HibernateProxy/TopLink weaved association)

In your EJB 3, you may have a single-valued association like this:

@Entity
public class MyEntity {

    @Id @GeneratedValue
    private Integer id;

    @OneToOne(fetch=FetchType.LAZY)
    private MyOtherEntity other;

    // Skipped code...
}

@Entity
public class MyOtherEntity {

    @Id @GeneratedValue
    private Integer id;

    // Skipped code...
}

If you load a large collection of MyEntity and do not need other references, this kind of declaration prevents unnecessary performance and memory overload. *Please refer to EJB 3/Hibernate documention in order to actually fetch those references when you need them. With GDS, you can keep those uninitialized references as is. For example:

[Bindable]
[RemoteClass(alias="path.to.MyEntity"]
public class MyEntity {

    private var __laziness:String = null;

    private var _id:int;
    private var _other:MyOtherEntity;

    // Skipped code...

    public override function readExternal(input:IDataInput):void {
        __laziness = input.readObject() as String;
        if (__laziness === null) {
            _id = input.readObject() as int;
            _other = input.readObject() as MyOtherEntity;
            // read remaining MyEntity fields...
        }
        else
            _id = input.readObject() as int;
    }
}

[Bindable]
[RemoteClass(alias="path.to.MyOtherEntity"]
public class MyOtherEntity {

    private var __laziness:String = null;

    private var _id:int;

    // Skipped code...

    public override function readExternal(input:IDataInput):void {
        __laziness = input.readObject() as String;
        if (__laziness === null) {
            _id = input.readObject() as int;
            // read remaining MyOtherEntity fields...
        }
        else
            _id = input.readObject() as int;
    }
}

When Flex deserializes your collection of MyEntity's with lazy loaded MyOtherEntity references, it reads a null laziness when it encounters a MyEntity instance since MyEntitys are all initialized; so it reads all MyEntity fields including the _other one. When it deserializes a MyOtherEntity instance referenced by a MyEntity, it reads a non-null laziness since MyOtherEntity is lazy loaded, so it only reads the MyOtherEntity id. Informations put in __laziness and _id are sufficient to recreate HibernateProxy instances when you give back MyEntity objects to the server for update.

Collections (List, Set, Bag, Map)

GDS also provides a way to keep uninitialized collections as is. When the externalizer encounters an uninitialized collection, it does not try to serialize its content and marks it as uninitialized. This information is kept in ActionScript 3 beans and when this bean is given back to the server (e.g., for an update), the externalizer recreates a lazy initialized collection in Java. This gives you a good control over serialization depth, as you do not face the risk of serializing the entire graph of your data, and prevents faulty updates (i.e., an empty collection is saved and deletes database data while it was only uninitialized).

For example, in this persistent set:

package test.granite.ejb3.entity;

import java.util.HashSet;
import java.util.Set;

...
import javax.persistence.CascadeType;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;

@Entity
public class Person extends AbstractEntity {
    ...
    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="person")
    private Set<Contact> contacts = new HashSet<Contact>();
    ...
    public Set<Contact> getContacts() {
        return contacts;
    }
    public void setContacts(Set<Contact> contacts) {
        this.contacts = contacts;
    }
}

// code for Contact skipped...

and:

package test.granite.ejb3.entity {

    ...
    import org.granite.collections.UIDSet;

    [Bindable]
    [RemoteClass(alias="test.granite.ejb3.entity.Person")]
    public class Person implements IExternalizable {

        ...
        private var _contacts:UIDSet;
        ...
        public function set contacts(value:UIDSet):void {
            _contacts = value;
        }
        public function get contacts():UIDSet {
            return _contacts;
        }
        ...
        public override function readExternal(input:IDataInput):void {
            ...
            _contacts = input.readObject() as UIDSet;
            ...
        }
        public override function writeExternal(output:IDataOutput):void {
            ...
            output.writeObject(_contacts);
            ...
        }
}

// code for Contact skipped...

org.granite.collections.UIDSet is part of a GDS flash library (granite.swc) that contains all AS3 classes you need in order to use the lazy loaded collections feature. When a given Set is initialized, it is serialized as a simple flex.messaging.io.ArrayCollection. Since UIDSet extends ArrayCollection and its RemoteClass alias is ArrayCollection, it is silently deserialized as a UIDSet.

If this Set is uninitialized, it is serialized as a org.granite.hibernate.HibernatePersistentSet or org.granite.toplink.TopLinkPersistentSer, which extends org.granite.collections.UIDSet but with a RemoteClass alias marked as org.granite.hibernate.HibernatePersistentSet or org.granite.toplink.TopLinkPersistentSet.

Other persistent collections, such as List, Bag, and Map, are handled in a similar manner. Please download graniteds-ejb3-1.2.0.zip and graniteds-src-1.2.0.zip to see example and sources.

GDS/EJB 3 uses mx.core.IUID for all entity beans. See a long Hibernate discussion here about equals/hashCode/collection problems and the use of UUIDs. This is only an implementation choice and you are free to code whatever you want.


Browse Space

- Pages
- Blog
- Labels
- Attachments
- Bookmarks
- Mail
- Advanced

Explore Confluence

- Popular Labels
- Notation Guide

Your Account

Log In

Other Features

Add Content


Copyright © 2011 Granite Data Services S.A.S. All Rights Reserved.