Как правильно инициализировать коллекцию сущностей (POJO) в проекте Spring-Hibernate? - PullRequest
6 голосов
/ 29 октября 2010

У меня есть класс POJO, скажем, Foo, у которого есть множество других экземпляров сущности, скажем, баров.Также существуют стандартные классы misc для такого проекта: service и dao для Foo и Bar.

Я хочу, чтобы BarService получал экземпляры Set of Bar, связанные с некоторыми Foo.Теперь у меня есть следующий код, который я считаю концептуально плохим.

 
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 вопроса: Где лучше инициализировать Foo's Set?Какие конкретные наборы и списки лучше подходят для таких целей?Какие концептуальные проблемы есть у моей текущей реализации, и как сделать лучше?

Заранее спасибо.

Ответы [ 3 ]

11 голосов
/ 31 октября 2010

Где лучше инициализировать набор Фу?

В большинстве случаев я инициализирую коллекции при объявлении их, что рекомендует Hibernate. Цитирование документации:

6,1. Постоянные коллекции

Hibernate требует постоянного коллекционные поля должны быть объявлены как тип интерфейса. Например:

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; }
}

Фактический интерфейс может быть java.util.Set, java.util.Collection, java.util.List, java.util.Map, java.util.SortedSet, java.util.SortedMap или что угодно как («все, что вам нравится» означает вас придется написать реализацию из * * Тысяча двадцать-один.) * * Тысяча двадцать две

Обратите внимание, как переменная экземпляра была инициализируется с экземпляром HashSet. Это лучший способ инициализировать коллекцию свойства недавно созданного (непостоянные) экземпляры. Когда ты сделать экземпляр постоянным, например, persist(), Hibernate на самом деле заменит HashSet с экземпляром Собственная реализация Hibernate Set.

Если оставить его null является частью вашего бизнеса, я бы предложил инициализировать его (общими) методами управления ссылками:

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);
    }
}

Какие конкретные наборы и списки лучше подходят для таких целей?

Все зависит от семантики, которая вам нужна. Set не допускает дублирование, List позволяет дублировать и вводит позиционную индексацию.

Какие концептуальные проблемы имеет моя текущая реализация и как ее улучшить?

  1. Я не выполнил бы назначение в получателе.
    • Если на этом этапе предполагается, что коллекция null, пусть она будет null.
  2. Я не вижу добавленной стоимости вашей услуги
    • почему бы просто не позвонить foo.getBars()?
    • зачем конвертировать коллекцию?
2 голосов
/ 29 октября 2010

Ваша сущность может быть простым набором полей с геттерами и сеттерами.Вам нужно позаботиться о том, как вы связываете свои объекты и подходе, который вы используете для заполнения объектов.
API ORM дает свободу использования объектов, а не SQL.Вы должны быть осторожны относительно того, когда вы должны инициализировать поля объекта.Например, если у вас есть объект человек, который включает в себя имя, возраст, коллекцию контактов и посещенных городов.В ситуации, когда вас интересуют имя и возраст человека, а не контакт и города, вам следует загружать только имя и возраст.Это означает, что контакты и города должны загружаться лениво.
Когда вы заинтересованы в контакте, вы загружаете только контакты, а не весь объект person или объект person.Вы хотели бы загружать Набор контактов только с помощью Dao / Service и явно определяя методы для загрузки определенного аспекта объекта (использование обратной связи).
Некоторые лучшие практики гибернации можно найти на Наилучшие практики ,Обновлено: 1) Сущность не заполняется самостоятельно.Один из популярных подходов - иметь DAO для выполнения этой работы.Ваша сущность может быть просто

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) Вы можете управлять транзакциями на другом уровне, также называемом сервисным уровнем.

1 голос
/ 29 октября 2010

Я склонен инициализировать коллекции на уровне сервиса, где я также поддерживаю обработку транзакций. Таким образом, у меня может быть метод в BaseDAO, который позволяет мне инициализировать любую коллекцию любой сущности в моих проектах, используя отражение, передавая имена коллекций в метод, который должен быть извлечен с нетерпением (инициализирован):

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;
    }

тогда вы можете инициализировать любую коллекцию из сервисного уровня, используя этот метод:

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

Более подробный пример: http://objecthunter.congrace.de/tinybo/blog/articles/69

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...