Вопрос идет как RoR, но я думаю, что этот вопрос больше применим к уровню запросов.Найти только записи, у которых есть все удаленные ассоциации
У меня есть модель
ModelA has_many ModelB
и я использую paranoid
камень в обоих из них.
Я пытаюсь выяснить все ModelA
, которые либо не ModelB
связаны или вообще не его ModelB
были удалены (поэтому deleted_at
не NULL).
Основываясь на this question, я смог добиться желаемого результата, но, читая запрос, мне не очень-то понятно, как он работает.
ModelA.joins('LEFT OUTER JOIN model_bs ON model_bs.model_a_id = model_as.id AND model_bs.deleted_at IS NULL')
.where('model_bs.model_a_id IS NULL')
.group(model_as.id)
Как уже упоминалось, чтение этого запроса не имеет смысла для меня, потому что присоединяется к условию, я использую также быть утратившим на ИНЕКЕ впоследствии.
Может кто-то, пожалуйста, помогите мне правильно установить запрос, и если это правильный путь, объясните мне, как разбивка запроса на правильный результат.
Update:
Как уже упоминалось на комментарии ниже, после того, как какой-то сырой SQL мне удалось понять, что происходит. Кроме того, написал мое AR решение, чтобы сделать его более ясным (по крайней мере, с моей точки зрения)
разбив его:
Этот запрос представляет собой регулярное левое внешнее соединение, которое возвращает все модели на левой независимо если есть ассоциация справа.
ModelA.joins('LEFT OUTER JOIN model_bs ON model_bs.model_a_id = model_as.id')
Добавление дополнительного условия в соединении
AND model_bs.deleted_at IS NULL
будет возвращать строки с ModelB
атрибутов, доступных, если есть один, связанный, в противном случае будет возвращать одну строку с только ModelA
.
Применение к этим строкам будет содержать только строки, не имеющие связанных моделей.
Примечание: В этом случае, используя атрибут model_a_id
или любой другой атрибут model_b
будет работать, но если идти по этому пути, я бы рекомендовал использовать атрибут, если связь существует, его всегда должны быть там. В противном случае у вас могут быть неправильные результаты.
Наконец, AR, что я в конечном итоге с помощью перевести то, что я хотел:
ModelA.joins('LEFT OUTER JOIN model_bs ON model_bs.model_a_id = model_as.id AND model_bs.deleted_at IS NULL')
.group('model_as.id')
.having('count(model_bs.id) = 0')
У меня была аналогичная проблема, вы можете проверить этот ответ: http://stackoverflow.com/a/15660222/580346 – mrzasa
После публикации здесь я продолжал искать объяснения. Немного сырья sql вместо AR помогло мне понять причину. – rpbaltazar