Подготовленное заявление о Postgresql в Rails

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

id = 5
st = ActiveRecord::Base.connection.raw_connection.prepare("DELETE FROM my_table WHERE id = ?")
st.execute(id)
st.close

К сожалению, он не работает с Postgresql - он выдает исключение в строке 2. Я искал решения и наткнулся на это:

id = 5
require 'pg'
conn = PG::Connection.open(:dbname => 'my_db_development')
conn.prepare('statement1', 'DELETE FROM my_table WHERE id = $1')
conn.exec_prepared('statement1', [ id ])

Это не удается в строке 3. Когда я печатаю исключение, как это

rescue => ex

бывший содержит это

{"connection":{}}

Выполнение SQL в командной строке работает. Есть идеи, что я делаю не так?

Заранее спасибо!

2 ответа

Решение

Если вы хотите использовать prepare тогда вам нужно сделать пару изменений:

  1. Драйвер PostgreSQL хочет видеть пронумерованные заполнители ($1, $2,...) не ставьте вопросительные знаки, и вам нужно дать вашему подготовленному заявлению имя:

     ActiveRecord::Base.connection.raw_connection.prepare('some_name', "DELETE FROM my_table WHERE id = $1")
    
  2. Последовательность вызова prepare с последующим exec_prepared:

    connection = ActiveRecord::Base.connection.raw_connection
    connection.prepare('some_name', "DELETE FROM my_table WHERE id = $1")
    st = connection.exec_prepared('some_name', [ id ])
    

Вышеупомянутый подход работает для меня с ActiveRecord и PostgreSQL, ваш PG::Connection.open версия должна работать, если вы подключаетесь правильно.

Еще один способ сделать цитату самостоятельно:

conn = ActiveRecord::Base.connection
conn.execute(%Q{
    delete from my_table
    where id = #{conn.quote(id)}
})

Это то, что ActiveRecord обычно делает за вашей спиной.

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

Если вы действительно пытаетесь удалить строку без помех, вы можете использовать delete:

удалять()

[...]

Строка просто удаляется с помощью SQL DELETE заявление о первичном ключе записи, и никакие обратные вызовы не выполняются.

Так что вы можете просто сказать это:

MyTable.delete(id)

и вы отправите простой delete from my_tables where id = ... в базу данных.

В дополнение к уже принятому ответу для тех, кто готовит запросы Google в Rails для пользовательских запросов, вот более простой способ сделать это через существующий интерфейс ActiveRecord (пример для Postgresql):

          ActiveRecord::Base.connection.exec_query("select * from table_name where id = $1", 
"example_query", [1], prepare: true)

А если поставитьbinding.pry, вы увидите, что подготовленный оператор действительно создан:

          ActiveRecord::Base.connection.exec_query('select * from pg_prepared_statements')

Ссылка: https://api.rubyonrails.org/v7.0.4.2/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html

Другие вопросы по тегам