Запрос, возвращающий пустую ассоциацию с NOT IN () и с IN () - PullRequest
0 голосов
/ 26 октября 2018

У меня есть модели Invitation и Person.Атрибуты и отношения, важные в этом вопросе, следующие:

# has sponsor_id, referral_email
class Invitation < ApplicationRecord
  belongs_to :sponsor, class_name: 'Person'
  belongs_to :referral, class_name: 'Person',
                        foreign_key: :referral_email, primary_key: :email
  scope :pending, -> { where.not(referral_email: Person.select(:email).distinct) }
end

# has id, email
class Person < ApplicationRecord
  has_many :sent_invitations, class_name: 'Invitation', 
                              foreign_key: :sponsor_id
  has_many :received_invitations, class_name: 'Invitation', 
                                  foreign_key: referral_email, 
                                  primary_key: :email
  has_many :referrals, class_name: 'Persona', through: :sent_invitations
  has_many :sponsors, class_name: 'Persona', through: :received_invitations
end

Я нашел запись Invitation, которой ее referral_email не было в таблице Person, а ее sponsor_id былодействительного Person.

Сценарий: Из @sponsor я попытался узнать, сколько у него sent_invitations.pending, но запрос вернул пустое отношение:

@sponsor.sent_invitations.pending.count # => 0

Но это результат других запросов, которые я выполняю при попытке отладки:

@sponsor.sent_invitations.count # => 1
@sponsor.referrals.count # => 0
@sponsor.sent_invitations.first.referral_email # => 'some_email@example.com'
Person.pluck(:email).include? @sponsor.sent_invitations.first.referral_email # => false

Я инвертировал условие scope из Invitation в следующее:

scope :pending, -> { where(referral_email: Person.select(:email).distinct) }

Но предполагаемый запрос продолжал возвращать пустое отношение

@person.sent_invitations.pending.count # => 0

Кто-нибудь знает, что может произойти?

Код работал нормально натестирование и мы обнаружили эту проблему на производстве.

Запросы

Запрос оригинальной попытки

SELECT "invitations".* FROM "invitations" WHERE "invitations"."sponsor_id" = $1 AND ("invitations"."referral_email" NOT IN (SELECT DISTINCT "person"."email" FROM "person"))

Запрос второй попытки

SELECT "invitations".* FROM "invitations" WHERE "invitations"."sponsor_id" = $1 AND ("invitations"."referral_email" IN (SELECT DISTINCT "person"."email" FROM "person"))

1 Ответ

0 голосов
/ 26 октября 2018

В таблице Persona было несколько записей с email: nil.Удаление их заставило запрос работать так, как ожидалось:

@person.sent_invitations.pending.count # => 1
@person.sent_invitations.first.referral_email # => 'some_email@example.com'
@person.sent_invitations.pending.first.referral_email # => 'some_email@example.com'

scope осталось таким же, каким оно было изначально:

scope :pending, -> { where.not(referral_email: Persona.select(:email).distinct) }

Я исследую, почему письма nil создавали этоповедение.Спасибо за помощь.

...