开发者

What is the correct way to initialize collection of an entity (POJO) in Spring-Hibernate project?

I have a POJO class, say Foo, which has a Set of other entity instances, say bars. Also there are standart misc classes for such project: service and dao for both Foo and Bar.

I want BarService to get the Set of Bar instances associated with some Foo. Now I have the following code, wich I believe is conceptually bad.

 
public class Foo {
    Set<Bar> bars;

    public Set<Bar> getBars() {
        if (bars == null)
            return ( bars = new HashSet() );
        return bars;
    }
}
 
public class BarServiceImpl {
    public List<Bar> getListOfBars(Foo foo) {
        return new ArrayList(foo.getBars());
    }
}

3 questions: Where it is better to initialize Foo's Set? What specific Sets and Lists are better for such purposes? What conceptual issues has my current implementation, and how to do better?

Than开发者_如何学Goks in advance.


Where it is better to initialize Foo's Set?

Most of time, I initialize a collections when declaring it, which is what Hibernate recommends. Quoting the documentation:

6.1. Persistent collections

Hibernate requires that persistent collection-valued fields be declared as an interface type. For example:

public class Product {
    private String serialNumber;
    private Set parts = new HashSet();

    public Set getParts() { return parts; }
    void setParts(Set parts) { this.parts = parts; }
    public String getSerialNumber() { return serialNumber; }
    void setSerialNumber(String sn) { serialNumber = sn; }
}

The actual interface might be java.util.Set, java.util.Collection, java.util.List, java.util.Map, java.util.SortedSet, java.util.SortedMap or anything you like ("anything you like" means you will have to write an implementation of org.hibernate.usertype.UserCollectionType.)

Notice how the instance variable was initialized with an instance of HashSet. This is the best way to initialize collection valued properties of newly instantiated (non-persistent) instances. When you make the instance persistent, by calling persist() for example, Hibernate will actually replace the HashSet with an instance of Hibernate's own implementation of Set.

If leaving it null is part of your business, my suggestion would be to initialize it in a (common) link management methods:

public class Foo {
    ...
    private Set<Bar> bars;
    ...
    public void addBar(Bar bar) {
        if (this.bars == null) {
            this.bars = new HashSet<Bar>();
        }
        this.bars.add(bar);
    }
}

What specific Sets and Lists are better for such purposes?

It all depends on the semantics you need. A Set doesn't allow duplicates, a List allows duplicates and introduces positional indexing.

What conceptual issues has my current implementation, and how to do better?

  1. I wouldn't perform an assignment in the getter.
    • If a collection is supposed to be null at that point, let it be null.
  2. I don't see the added value of your service
    • why not just calling foo.getBars()?
    • why converting the collection?


Your entity could be simple set of fields with getters and setters. What you need to take care of is how you relate your objects and approach you take to populate objects.
ORM APIs gives liberty of using Objects rather than SQL. You should be careful as to when you should choose to initialize the fields of an Object. For example if you have an object person, which comprises of name, age, collection of contacts and cities visited. In a situation where you are interested in name and age of the person and not contact and cities, you should load name and age only. Which implies that contacts and cities should be lazy loaded.
When interested in contact you load only contacts and not the entire person object or through person object. You would want to load Set of contacts only using Dao/Service and explicitly defining methods to load specific aspect of the object (use of reverse association).
Some best hibernate practices can be found at Best Practices. Updated: 1) Entity does not populate on its own. One of the popular approach is to have DAO to do this Job. Your Entity could simple be

public class Foo {
    private Set<Bar> bar=new HashSet<Bar>();
    public Set<Bar> getBar {
        return bar;
    }
    public void setBar(Bar bar) {
        this.bar = bar;
    }
}

2) You can have transaction managed in another layer also referred as Service layer.


i tend to initialize the collections in the service layer where i keep the transaction handling as well. So i can have a method in my BaseDAO which lets me initialize any collection of any Entity in my projects using reflection, by passing the collection names into the method which are to be fetched eagerly (initialized):

public <T extends Object> T getEntity(Class<T> clazz,long id,String[] collectionsToBeInitialized){
        T entity=(T) this.getCurrentSession().createCriteria(clazz).add(Restrictions.idEq(id)).setFetchMode(collectionsToBeInitialized[0], FetchMode.JOIN).uniqueResult();
        int length=collectionsToBeInitialized.length;
        for (int idx=1;idx<length;idx++){
            String collectionName=collectionsToBeInitialized[idx];
            try {
                Method m = clazz.getMethod("get" + collectionName.substring(0, 1).toUpperCase() + collectionName.substring(1),(Class<T>) null);
                Hibernate.initialize(m.invoke(entity,(Object[]) null));
            } catch (NoSuchMethodException e) {
                LOG.error("Could not initialize collection " + collectionName + " of class Event", e);
            } catch (InvocationTargetException e) {
                LOG.error("Could not initialize collection " + collectionName + " of class Event", e);
            } catch (IllegalAccessException e) {
                LOG.error("Could not initialize collection " + collectionName + " of class Event", e);
            }
        }
        return entity;
    }

then you can initialize any collection from the service layer using this method:

MyEntity ent=getEntity(MyEntity.class,id,new String[]{"collection1","collection2"});

A more detailed example: http://objecthunter.congrace.de/tinybo/blog/articles/69

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜