Запрос ActiveRecord возвращает разные результаты для двух экземпляров одного и того же объекта базы данных в памяти. - PullRequest
0 голосов
/ 05 августа 2020

В сеансе консоли, повторяемо, если я обращаюсь к определенному экземпляру модели, извлекая его из массива, я получаю неверные результаты при вызове метода для этого объекта. Однако, если я загружу тот же объект непосредственно из базы данных с помощью find(id), тот же метод вернет правильные результаты.

Как это может произойти? Сумасшедшая часть действительно в том, что для первых двух элементов массива все нормально. Как вы можете видеть в конце вывода консоли, результаты для первых двух элементов в массиве (все они одного типа и все имеют два Link дочерних элементов) имеют смысл. Последние пять не должны быть пустыми.

# Instance from an array
irb(main):417:0> the_array = User.find(89).utterances.select{|u| u.links.count > 1}
=> [#<Utterance id: ...>, #<Utterance id: 6931, ...>, #<Utterance id: 6935, ...>, #<Utterance id: 6944, ...>, #<Utterance id: 6955, ...>, #<Utterance id: 6989, ...>, #<Utterance id: 7014, ...>]

irb(main):418:0> from_array = the_array.last
=> #<Utterance id: 7014, ...>

irb(main):419:0> from_array.class
=> Utterance(id: integer, index: integer, begins_at: float, text: text, created_at: datetime, updated_at: datetime, ends_at: float, recording_id: integer)

irb(main):420:0> from_array.links.class
=> Link::ActiveRecord_Associations_CollectionProxy

irb(main):421:0> from_array.links
=> #<ActiveRecord::Associations::CollectionProxy []>

# Instance from find
irb(main):422:0> from_find = Utterance.find(7014)
  Utterance Load (1.8ms)  SELECT "utterances".* FROM "utterances" WHERE "utterances"."id" = $1 LIMIT $2  [["id", 7014], ["LIMIT", 1]]
=> #<Utterance id: 7014, ...>

irb(main):423:0> from_find.class
=> Utterance(id: integer, index: integer, begins_at: float, text: text, created_at: datetime, updated_at: datetime, ends_at: float, recording_id: integer)

irb(main):424:0> from_find.links.class
=> Link::ActiveRecord_Associations_CollectionProxy

irb(main):424:0> ap from_find.links
[
    [0] #<Link:0x000055fc7f154150> {
                  :id => 212,
                  #...
    },
    [1] #<Link:0x000055fc7f15feb0> {
                  :id => 213,
                  #...
    }
]
irb(main):425:0>

# But for the first two elements of the array, no problem
irb(main):486:0> the_array.each{|u| puts ap u.links}
[
    [0] #<Link:0x000055fc80cc34e0> {
                  :id => 208,
                  ...
    },
    [1] #<Link:0x000055fc80cc3328> {
                  :id => 209,
                  ...
    }
]

[
    [0] #<Link:0x000055fc80cc7180> {
                  :id => 211,
                  ...
    },
    [1] #<Link:0x000055fc80cc6fc8> {
                  :id => 210,
                  ...
    }
]

[]

[]

[]

[]

[]

Ответы [ 2 ]

0 голосов
/ 05 августа 2020

Оказывается, мой консольный сеанс каким-то образом поврежден. Я выполнил следующие шаги, и затем все вызовы метода links на модели Utterance из массива работали должным образом.

  1. Выйти из консоли
  2. rails c
  3. Вставьте этот код:
    the_array = Recording.find(89).utterances.select{|u| u.links.count > 1}
    from_array = the_array.last
    from_array.class
    from_array.links.class
    from_array.links
    from_find = Utterance.find(7014)
    ap from_find.id
    ap from_find.class
    from_find.links.class
    ap from_db.links
    the_array.each{|u| puts ap u.links}
    

Шаг 3 - то же самое, что я делал в предыдущем сеансе консоли. Видимо, я каким-то образом заблокировал стек предыдущей сессии.

0 голосов
/ 05 августа 2020

Ассоциации кэшируются . from_array.links получает кэшированный набор с момента его первого вызова, from_find.links получает бесплатную sh копию из базы данных. Предположительно, некоторые ссылки были добавлены между первым вызовом from_array.links и from_find.links.

Если вы запустите from_array.links.reload, он обновит sh кешированную ассоциацию, и вы должны получить тот же результат, что и from_find.links.

Вы можете избежать устаревших кешей ассоциаций, изменив ассоциацию с помощью методов в коллекции . Например, если вы хотите создать новую ссылку ...

# This will update the utterance.links cache
utterance.links.create!( some: "attribute" )

# This will not.
link = Links.create!(
  some: "attribute",
  utterance: utterance
)

# This will.
utterance.links << link

# This will not.
link.destroy

# This will.
utterance.links.destroy(link)

Обратите внимание, что: User.find(89).utterances.select{|u| u.links.count > 1} неэффективно. Он должен загружать каждое высказывание и подсчитывать его ссылки по отдельности, что называется запросом N + 1 (или 1 + N).

Более эффективно сделать это с объединением и группой с помощью.

User.find(89).utterances
  .joins(:links)
  .group('utterances.id')
  .having('count(utterances.id) > 1')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...