【问题标题】:Calling PL/pgSQL Stored Procedures from Ruby on Rails从 Ruby on Rails 调用 PL/pgSQL 存储过程
【发布时间】:2023-04-01 13:00:02
【问题描述】:

我正在从事一个项目,我是 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。

标签: ruby-on-rails ruby stored-procedures plpgsql rails-postgresql


【解决方案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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-29
    • 1970-01-01
    • 1970-01-01
    • 2014-05-07
    • 2014-05-11
    • 2011-01-08
    • 1970-01-01
    • 2018-04-05
    相关资源
    最近更新 更多