Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > Hibernate DetachedCriteria - дублируются записи


Автор: brejnev 10.1.2008, 16:16
Разбираюсь с критериями в Hibernate3.

Создаю DetachedCriteria, делаю выборку. В итоге - набор дублирующихся сущностей, причем в БД все записи уникальны. Дублирование идет как-попало и от чего зависит так и не понял. 
В результяте упрощения запроса остался такой код:

Код

DetachedCriteria criteria = DetachedCriteria.forClass(QuestionnairePerson.class,"person");
Collection result = getHibernateTemplate().findByCriteria(criteria);


QuestionnairePerson

Код

@Entity
@Table(name = "questionnaireperson")
})
public class QuestionnairePerson implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "fkey", nullable = false)
    private Integer key;

   public QuestionnairePerson() {
    }

    public QuestionnairePerson(Integer fkey) {
        this.key = fkey;
    }

    @Override
    public int hashCode() {
        return getKey().hashCode();
    }

    @Override
    public boolean equals(Object object) {

        if (!(object instanceof QuestionnairePerson)) {
            return false;
        }

        return this.getKey().equals(object);
    }
...
}


В гугле смотрел, так и не поборол баг.

 Работает все нормально если задать такую штуку
Код

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);


Но мне это не нравится, что-то тут не так.

Автор: ibodrov 10.1.2008, 18:41
Дело не в DetachedCriteria.

Посмотрите, какой SQL генерит Hibernate ("hibernate.show_sql"), наверняка там будут дублирующиеся записи из-за JOIN'ов.

Автор: brejnev 10.1.2008, 20:49
Цитата

Дело не в DetachedCriteria.

Посмотрите, какой SQL генерит Hibernate ("hibernate.show_sql"), наверняка там будут дублирующиеся записи из-за JOIN'ов.


Хм, завтра на работу приду, попробую.....

Поведение похоже на join, но откуда ему там взяться? Неужели hibernate присоединяет все связанные таблицы smile 

Автор: brejnev 11.1.2008, 08:31
Код

select answerfill0_.f_person as f4_4_, answerfill0_.fkey as fkey4_, answerfill0_.fkey as fkey127_3_, answerfill0_.f_answer as f3_127_3_, answerfill0_.f_person as f4_127_3_, answerfill0_.fvalue as fvalue127_3_, answer1_.fkey as fkey125_0_, answer1_.f_nextquestion as f3_125_0_, answer1_.f_question as f4_125_0_, answer1_.ftext as ftext125_0_, question2_.fkey as fkey128_1_, question2_.f_questionnaire as f3_128_1_, question2_.ftext as ftext128_1_, question2_.f_type as f4_128_1_, question3_.fkey as fkey128_2_, question3_.f_questionnaire as f3_128_2_, question3_.ftext as ftext128_2_, question3_.f_type as f4_128_2_ 
from tanswerfilled answerfill0_ left outer join tanswer answer1_ on answerfill0_.f_answer=answer1_.fkey 
left outer join tquestion question2_ on answer1_.f_nextquestion=question2_.fkey 
left outer join tquestion question3_ on answer1_.f_question=question3_.fkey where answerfill0_.f_person=?


Вот такой sql-код генерит хитбернейт-критерий в первом посте. Как ему сказать, чтобы он не соединял join-ом таблицы? Мне всего-лишь надо выбрать сущности из одой таблицы.

Автор: iluvatar 11.1.2008, 15:58
насколько помню у Criteria нет какого-либо вменяемого решения distinct-проблемы
сам когда-то задавался подобным вопросом. как временный вариант тогда выбрал такой метод:
    сначала выбираем ТОЛЬКО id:
         
Код

                    Criteria crit = session.createCriteria(Class.class)
                            ....
                            .setProjection(Projections.distinct(Projections.projectionList().add(Projections.id()) ))
                            .setFirstResult(startPos).setMaxResults(maxResults)
         
  
    а потом  по списку id получаем те записи какие хотим.

НО! если существует какой-либо order by, то все поля по которым идет сортировка необходимо указать в projectionList():
Код

                    Criteria crit = session.createCriteria(Class.class)
                             ....
                            .setProjection(Projections.distinct(Projections.projectionList()
                                    .add(Projections.id())
                                    .add(Projections.property("field1"))
                                    .add(Projections.property("field2"))))
                            .setFirstResult(startPos).setMaxResults(maxResults)
                            .addOrder(Order.asc("field1"))
                            .addOrder(Order.asc("field2"));

  получаем список полей, вручную получаем список ТОЛЬКО из первых элементов списка (только id), по id получаем список записей.

Есть еще один вариант с ипсользованием Criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY), но этоот способ выполняет distinct ПОСЛЕ выполнения запроса, т.е. средствами не БД, а Hibernate, что не подходит если осуществляется постраничное ранжирование.

Кстати, это была одна из причин перехода на HQL, чего и вамсоветую.

Добавлено через 2 минуты и 31 секунду
Цитата(brejnev @ 11.1.2008,  08:31)
Код

select answerfill0_.f_person as f4_4_, answerfill0_.fkey as fkey4_, answerfill0_.fkey as fkey127_3_, answerfill0_.f_answer as f3_127_3_, answerfill0_.f_person as f4_127_3_, answerfill0_.fvalue as fvalue127_3_, answer1_.fkey as fkey125_0_, answer1_.f_nextquestion as f3_125_0_, answer1_.f_question as f4_125_0_, answer1_.ftext as ftext125_0_, question2_.fkey as fkey128_1_, question2_.f_questionnaire as f3_128_1_, question2_.ftext as ftext128_1_, question2_.f_type as f4_128_1_, question3_.fkey as fkey128_2_, question3_.f_questionnaire as f3_128_2_, question3_.ftext as ftext128_2_, question3_.f_type as f4_128_2_ 
from tanswerfilled answerfill0_ left outer join tanswer answer1_ on answerfill0_.f_answer=answer1_.fkey 
left outer join tquestion question2_ on answer1_.f_nextquestion=question2_.fkey 
left outer join tquestion question3_ on answer1_.f_question=question3_.fkey where answerfill0_.f_person=?


Вот такой sql-код генерит хитбернейт-критерий в первом посте. Как ему сказать, чтобы он не соединял join-ом таблицы? Мне всего-лишь надо выбрать сущности из одой таблицы.

насчет подключения вложенных таблиц отвечают lazy и fetch в мэппинге.

Автор: mariyasmirnova01 24.9.2015, 11:55
Мне помогла статья http://novainfo.ru/archive/3/poisk-dubliruyushchegosya-koda

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)