从 Ruby on Rails 调用 PL/pgSQL 存储过程
Posted
技术标签:
【中文标题】从 Ruby on Rails 调用 PL/pgSQL 存储过程【英文标题】:Calling PL/pgSQL Stored Procedures from Ruby on Rails 【发布时间】:2013-06-15 02:52:27 【问题描述】:我正在从事一个项目,我是 PostgreSQL 环境中的数据库设计师/管理员。领导决定使用 Rails 进行应用程序逻辑,并招聘了一名 Rails 程序员。
Rails 程序员说,他通常编写所有应用程序代码,不喜欢有人向他传递存储过程所带来的缺乏控制,而且他从未在 Rails 中这样做过。
数据库使用了大量的继承/EERM,因此存储过程和触发器将使他的工作变得更加轻松,此外还可以从使用 procs 中获得性能优势。
我有四个问题:
1) 如何从 Rails 调用 pl/pgSQL 存储过程而没有返回值
2) 如何从 Rails 中调用具有单个返回值(1 行/1 列)的 pl/pgSQL 存储过程
3) 如何从 Rails 调用具有 1 行多列返回值的 pl/pgSQL 存储过程。
4) 如何使用 OUT 参数从 Rails 调用 pl/pgSQL 存储过程?
谢谢!
【问题讨论】:
除非你能说服你的 Rails 程序员使用像Sequel 这样的东西,否则你会度过一段糟糕的时光。默认的 Rails ORM (ActiveRecord) 不认为数据库应该包含任何逻辑,并且不理解比select *
和简单连接更复杂的任何东西,如果您违反约定使用“花哨”的东西,比如触发器、存储过程,甚至是准备好的语句。
是的...基于过程和继承的 DB + ActiveRecord 将引导您直接进入thedailywtf.com 领域。你必须接受使用 Rails 的决定(大概是它的 ActiveRecord ORM),然后把你的数据库设计扔到窗外,然后制作一个遵循 ActiveRecord 约定的设计(没有像“外键”或“约束”这样愚蠢的东西,反正谁想要它们?)。或者,改变决定,看看你是否可以让他们至少使用理智的 ORM。
【参考方案1】:
您好,我正在使用此代码来处理 PgSQL 存储过程 这涵盖了除了你最后一个问题之外的所有内容
class SpActiveRecord < ActiveRecord::Base
self.abstract_class = true
#without return value
def self.execute_sp(sql, *bindings)
perform_sp(:execute, sql, *bindings)
end
#select many return values
def self.fetch_sp(sql, *bindings)
perform_sp(:select_all, sql, *bindings)
end
#select single return value
def self.fetch_sp_val(sql, *bindings)
perform_sp(:select_value, sql, *bindings)
end
protected
def self.perform_sp(method, sql, *bindings)
if bindings.any?
sql = self.send(:sanitize_sql_array, bindings.unshift(sql))
end
self.connection.send(method, sql)
end
end
例子
class Invoice < SpActiveRecord
def create_or_update
raise ReadOnlyRecord if readonly? or !new_record?
self.id = fetch_sp_val("SELECT * FROM billing.invoice_generate(?,?,?)",
self.account_id,
self.start_date,
self.end_date)
@new_record = false
true
end
end
【讨论】:
以上是关于从 Ruby on Rails 调用 PL/pgSQL 存储过程的主要内容,如果未能解决你的问题,请参考以下文章
Ruby on Rails:将数据调用到 javascript 中的首选方法?
Ruby on Rails 如何使用 yield 进行布局?