Grails hasMany и критерии не работают должным образом

У меня есть две модели с отношением hasMany

class Puturru implements Serializable {
    String name

    Set<Fua> fuas

    static hasMany = [fuas: Fua]

    static constraints = {
        fuas(nullable: true)
    }
}

И

class Fua {

    String name

    static constraints = {
    }
}

При запуске следующего теста я получаю LazyInitializationException

 void "test something"() {
    given:
    def puturrus

    Puturru.withNewSession { session ->
        p = Puturru.build()
        Fua f
        for (int i = 0; i < 10; i++) {
            f = Fua.build()
            p.addToFuas(f)
        }
        f.save(failOnError: true, flush: true)

    }

    when:
    Puturru.withNewSession {

        puturrus = Puturru.createCriteria().listDistinct {

            fetchMode("fuas", FetchMode.JOIN)
        }

    }

    then:
    Puturru.withNewSession {
        assert puturrus.fuas*.name.size() > 0

    }

    p.fuas.each { it.delete() }
    p.delete()
}

Если я установлю отображение puturrus

static mapping = {
    fuas lazy: false
}

Затем извлекаются все элементы, хотя он использует несколько вариантов выбора, в противном случае он использует этот запрос

select ...
from puturru ...
left outer join puturru_fua fuas2_ on this_.id=fuas2_.puturru_fuas_id

Я не могу установить сопоставление в реальном приложении, потому что я не хочу получать все записи во всех случаях. Мне кажется, что я что-то упускаю, чтобы критерии пошли дальше промежуточной таблицы.

Я использую Grails 2.3.6 и спящий режим 3.6.10.8.

Кто-нибудь знает, почему не получают объекты "fuas"?

РЕДАКТИРОВАТЬ 1: Дополнительная информация

Я пытался внести некоторые изменения в домены и проверить, чтобы выяснить, в чем проблема.

После предложения @sudhir я начал играть с объединениями. Я изменил критерии на что-то вроде

    puturrus = Puturru.createCriteria().listDistinct {
        fuas {
        }
    }

Затем запрос, сгенерированный gorm и hibernate, был

select ...
from puturru this_
inner join puturru_fua fuas3_ on this_.id=fuas3_.puturru_fuas_id
inner join fua fuas_alias1_ on fuas3_.fua_id=fuas_alias1_.id

На этот раз мы получили все записи, но не их связь с доменами puturrus. Мы компрометируем и помещаем второй запрос только для получения ассоциаций, поэтому на данный момент второй блок сеанса

Puturru.withNewSession {

    puturrus = Puturru.createCriteria().listDistinct {
        fuas {
        }
    }

    Puturru.createCriteria().listDistinct {
        fetchMode("fuas", FetchMode.JOIN)
    }
}

Это намного лучше, чем мой предыдущий подход, который перебирал все путаницу и все возражения в сеансе критериев, но я думаю, что он все еще неоптимален, поэтому есть ли способ получить как данные, так и ассоциации в одном запросе ?


person esauro    schedule 20.03.2015    source источник
comment
Вы не сохраняете Путтуру в конце данного блока. Почему вы используете withNewSession во всех этих местах, это вообще не требуется. Кроме того, будьте осторожны, объединение в fetchmode может дать дублирующиеся результаты, вы можете использовать fetchmode FM.SELECT   -  person Sudhir N    schedule 23.03.2015
comment
Собственно метод сборки, который является частью плагина для сборки тестовых данных, save. Я сделал этот код только для того, чтобы воспроизвести ситуацию, которую я обнаружил в реальном приложении, в реальном мире есть веские причины разделить три сеанса. Я пробовал FM.SELECT тоже без успеха.   -  person esauro    schedule 23.03.2015
comment
Попробуйте добавить в критерий join 'fuas' и удалите fetchMode, чтобы это было похоже на критерии.listDistinct {join fuas}   -  person Sudhir N    schedule 23.03.2015
comment
@sudhir, если я это сделаю, запрос имеет два внутренних соединения, но все равно не работает. Однако, если я проверю элементы с помощью отладчика, этот запрос select fuas0_.puturru_fuas_id as puturru1_1_0_, fuas0_.fua_id as fua2_0_ from puturru_fua fuas0_ where fuas0_.puturru_fuas_id=?, а затем элементы будут доступны вне сеанса.   -  person esauro    schedule 23.03.2015


Ответы (2)


Вы можете использовать следующий hql

Puturru.executeQuery("select p from Puturru p inner join fetch p.fuas as f where p.id = :id", [id:id])

Если вы хотите, чтобы все Puturru удалить где условие

person Sudhir N    schedule 24.03.2015
comment
Вы правы, это было бы полезно, если бы код был таким простым, как эти примеры, но реальный код намного сложнее и включает в себя несколько других доменов, и нам не нужен такой большой hql-запрос. - person esauro; 24.03.2015

Мы нашли правильное решение, используя createAlias

Puturru.withNewSession {
    puturrus = Puturru.createCriteria().listDistinct {
        createAlias("fuas", "fuas", CriteriaSpecification.LEFT_JOIN)
    }
}

На самом деле это ошибка в Hibernate 3.6, уже исправленная в Hibernate 4.

person esauro    schedule 24.03.2015