Может ли динамический поиск Grails быть взломан кодом приложения?

В проекте, над которым я работаю, есть некоторый код, в котором динамический поиск ведет себя иначе в одной ветке кода, чем в другой.

Эта строка кода возвращает всех моих рекламодателей (их 8), независимо от того, в какой ветке я нахожусь.

Advertiser.findAllByOwner(ownerInstance)

Но когда я начинаю добавлять условия, все становится странно. В ветке A следующий код возвращает всех моих рекламодателей:

Advertiser.findAllByOwner(ownerInstance, [max: 25])

Но в ветке B этот код возвращает только 1 рекламодателя.

Кажется невероятным, чтобы изменения в коде приложения могли повлиять на работу динамического поиска. Я ошибся? Есть ли что-то еще, что может привести к тому, что это не сработает?

Изменить

Меня попросили опубликовать определения моих классов. Вместо того, чтобы публиковать все это, я собираюсь опубликовать то, что я считаю важной частью:

static mapping = {
    owner fetch: 'join'
    category fetch: 'join'
    subcategory fetch: 'join'
}

static fetchMode = [
      grades: 'eager',
      advertiserKeywords: 'eager',
      advertiserConnections: 'eager'
]

Этот код присутствовал в ветке B, но отсутствовал в ветке A. Когда я вытаскиваю его, все работает, как и ожидалось.

Я решил еще немного покопаться с этим кодом, чтобы посмотреть, что я могу наблюдать. Я нашел кое-что интересное, когда использовал withCriteria вместо динамического поиска:

Advertiser.withCriteria{owner{idEq(ownerInstance.id)}}

Я обнаружил, что это вернуло тысячи дубликатов! Итак, я попытался использовать listDistinct:

Adviertiser.createCriteria().listDistinct{owner{idEq(ownerInstance.id)}}

Теперь это возвращает всех 8 моих рекламодателей без дубликатов. Но что, если я попытаюсь ограничить результаты?

Advertiser.createCriteria().listDistinct{
    owner{idEq(ownerInstance.id)}
    maxResults 25
}

Теперь это возвращает один результат, как это делает мой динамический поиск. Когда я разогнал maxResults до 100 тыс., теперь я получаю все 8 результатов.

Так что же происходит? Кажется, что объединение или нетерпеливая выборка (или и то, и другое) сгенерировали sql, который вернул тысячи дубликатов. Динамические средства поиска Grails по умолчанию должны возвращать разные результаты, поэтому, когда я не ограничивал их, я не заметил ничего странного. Но как только я установил ограничение, поскольку записи были упорядочены по идентификатору, все первые 25 записей были бы повторяющимися записями, а это означает, что будет возвращена только одна отдельная запись.

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


person Samo    schedule 19.04.2013    source источник
comment
Можете поделиться определением рекламодателя? Вы уверены, что это один и тот же владелецInstance в обоих случаях?   -  person    schedule 19.04.2013
comment
Ваше приложение не должно влиять на это поведение. Более вероятными причинами могут быть такие вещи, как то, что вы указываете на две разные базы данных в разных ветвях, или, возможно, одна ветвь имеет проверки, которых нет в другой, и вы создаете 8 рекламодателей в приспособлении или Bootstrap, и создание завершается ошибкой.   -  person proflux    schedule 19.04.2013
comment
Помните, что первая строка кода дает мне всех моих рекламодателей, независимо от того, в какой ветви я нахожусь. Только когда я добавляю условия, я наблюдаю такое поведение в ветви B. Поэтому я думаю, что это исключает возможности, упомянутые в комментариях выше.   -  person Samo    schedule 19.04.2013
comment
Вы можете включить ведение журнала sql для проверки сгенерированных запросов.   -  person    schedule 20.04.2013
comment
Самый распространенный ответ: 2 разные базы данных. И согласен с proflux: ваше приложение не должно влиять на это поведение.   -  person Mr. Cat    schedule 22.04.2013
comment
@SérgioMichels: я включил ведение журнала sql, и единственная разница, которую я вижу в запросах, - это конец. Запрос без условия max показывает where this_.owner_id=?, а запрос с [max: 25] показывает where this_.owner_id=? limit ?   -  person Samo    schedule 22.04.2013
comment
@ Само, можешь поделиться определением своих классов?   -  person    schedule 22.04.2013
comment
@SérgioMichels: я обновил свой вопрос, указав код виновника и некоторые сделанные мной наблюдения. Любые идеи приветствуются. Спасибо!   -  person Samo    schedule 23.04.2013


Ответы (2)


Я обнаружил, что нетерпеливая выборка была добавлена ​​(многоуровневая глубина), чтобы ускорить рендеринг некоторых отчетов, потому что выполнялись сотни запросов. Были предприняты попытки жадной выборки по запросу, но другим разработчикам было трудно углубиться более чем на один уровень, используя средства поиска или критерии Grails.

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

Следующий вопрос, как? Это не очень хорошо поддерживается в Grails, но этого можно добиться, просто используя класс Hibernate Criteria. Вот суть:

        def advertiser = Advertiser.createCriteria()
            .add(Restrictions.eq('id', advertiserId))
            .createCriteria('advertiserConnections', CriteriaSpecification.INNER_JOIN)
                .setFetchMode('serpEntries', FetchMode.JOIN)
                .uniqueResult()

Теперь advertiserConnections рекламодателя будут получать с нетерпением, и advertiserConnections' serpEntries также будут с нетерпением ждать. Вы можете спуститься по дереву так далеко, как вам нужно. Затем вы можете оставить свои классы ленивыми по умолчанию, что определенно должно быть для hasMany сценариев.

person Samo    schedule 25.04.2013

Поскольку ваш запрос извлекает дубликаты, есть вероятность, что это ограничение в 25 записей вернет одни и те же данные, следовательно, ваша отдельная запись уменьшится до одной записи.

Попробуйте определить equals() и hashCode() для своих классов, особенно если у вас есть составной первичный ключ или используется как hasMany.

Я также предлагаю вам попробовать исключить возможности. Удалите выборку и нетерпеливое одно за другим, чтобы увидеть, как это повлияет на ваши данные результатов (без ограничений).

person Community    schedule 23.04.2013