11

Estoy familiarizado con la larga relación de amor-odio entre Ruby on Rails, controladores DB (MS) y procedimientos almacenados, y he estado desarrollando aplicaciones Rails desde la versión 2.3.2.¿Por qué los procedimientos almacenados aún no son compatibles con Rails (3+)?

Sin embargo, de vez en cuando surge una situación donde un SP es simplemente una mejor opción que combinar datos en el nivel de aplicación (mucho más lento). Específicamente, la ejecución de informes que combina datos de múltiples tablas suele ser más adecuada para un SP.

¿Por qué los procedimientos almacenados están tan mal integrados en Rails o en la gema MySQL? Actualmente estoy trabajando en un proyecto con Rails 3.0.10 y MySQL2 gem 0.2.13, pero hasta donde puedo ver, incluso las últimas versiones de Edge Rails y MySQL gem 0.3+ todavía generan rabietas cuando usas SP.

El problema que ha sido, y sigue siendo, es que la conexión de la base de datos se pierde después de que se llama a un SP.

>> ActiveRecord::Base.connection.execute("CALL stored_proc") 
=> #<Mysql::Result:0x103429c90> 
>> ActiveRecord::Base.connection.execute("CALL stored_proc") 
ActiveRecord::StatementInvalid: Mysql::Error: Commands out of sync; 
[...] 
>> ActiveRecord::Base.connection.active? 
=> false 
>> ActiveRecord::Base.connection.reconnect! 
=> nil 
>> ActiveRecord::Base.connection.execute("CALL proc01") 
=> #<Mysql::Result:0x1034102e0> 
>> ActiveRecord::Base.connection.active? 
=> false 

¿Este es un problema realmente difícil de abordar, técnicamente, o es una opción de diseño de Rails?

+0

Fwiw: Desde feb 2006, entrevista DHH: "estoy totalmente desinteresado en las características de lujo como procedimientos almacenados , desencadenantes y similares "- http://dev.mysql.com/tech-resources/interviews/david-heinemeier-hansson-rails.html –

+0

También [" Considero que los procedimientos almacenados y las restricciones son viles e imprudentes destructores de la coherencia "] (http://web.archive.org/web/20060418215514/http://www.loudthinking.com/arc/000516.html) ... – dbr

+7

2006 ... Principios antiguos (sí, 6 años es antiguo en un mundo lik e Rails ') rara vez tienen sentido contra la evolución de la tecnología (640k es suficiente, ¿alguien?) Existe el dominio teórico y práctico. En teoría, estoy absolutamente de acuerdo con el paradigma de Rails, pero a veces la mejor base de datos normalizada ofrece el peor rendimiento en el mundo real. Cuando un SP puede recopilar los datos de mi informe en menos de 100 ms y hacer 'el camino de Rails' toma más de 2-3 segundos y se realizan varias consultas en una base de datos compartida, sé quién es el ganador claro. – ChrisDekker

Respuesta

10

Los procedimientos almacenados se admiten en rieles. El error de falta de sincronización que está recibiendo se debe a que el indicador MULTI_STATEMENTS para MySQL no está habilitado de manera predeterminada en Rails. Este indicador permite que los procedimientos devuelvan más de 1 conjunto de resultados.

Ver aquí para un ejemplo de código en la forma que le permita: https://gist.github.com/wok/1367987

Los procedimientos almacenados trabajan fuera de la caja con MS SQL Server.

He estado utilizando procedimientos almacenados en casi todos mis proyectos de rieles basados ​​en mySQL y SQL Server sin ningún tipo de emisión.

3

Esto es para postgres para ejecutar un procedimiento almacenado que devuelve instancias de MyClass.

sql=<<-SQL 
select * from my_cool_sp_with_3_parameters(?, ?, ?) as 
foo(
    column_1 <type1>, 
    column_2 <type2> 
) 
SQL 

MyClass.find_by_sql([sql, param1, param2, param3]); 

Reemplazar la lista de columnas dentro de foo() con las columnas de su modelo y los resultados de procedimientos almacenados. Estoy seguro de que esto podría hacerse genérico al inspeccionar las columnas de la clase.

0

Aquellos que reciben errores de sincronización pueden tener procedimientos que generan resultados múltiples. Usted tendrá que hacer algo como esto para manejarlos:

raise 'You updated Rails. Check this duck punch is still valid' unless Rails.version == "3.2.15" 
module ActiveRecord 
    module ConnectionAdapters 
    class Mysql2Adapter 
     def call_stored_procedure(sql) 
     results = [] 
     results << select_all(sql) 
     while @connection.more_results? 
      results << @connection.next_result 
     end 
     results 
     end 
    end 
    end 
end 

llamada así:

ActiveRecord::Base.connection.call_stored_procedure("CALL your_procedure('foo')") 
Cuestiones relacionadas