Получить вставленный ID от Sequel prepare - PullRequest
1 голос
/ 23 августа 2011

У меня есть готовый оператор вставки в сиквеле (с использованием Oracle).

prepared_statement = DB[:table_name].prepare(:insert, :name, :value=>:$value)

Когда я называю это, строка добавляется просто отлично.

prepared_statement.call :value=>'Some value'

У меня есть триггер и последовательность, поэтому идентификатор будет сгенерирован автоматически. Я хотел бы вернуть строку (или идентификатор), которую я только что добавил, но я не вижу, как. Я не могу использовать insert, потому что значение является CLOB и может быть больше 4000 символов.

Ответы [ 3 ]

1 голос
/ 16 сентября 2011

В JRuby, используя адаптер JDBC, вы можете переопределить вставку и передать возвращаемое предложение.Сложность в том, что вы не всегда знаете, какой первичный ключ находится на этом уровне, поэтому вам, возможно, придется использовать ROWID или запросить все столбцы обратно.

В итоге вы получите нечто, похожее на это:

module Sequel
  module JDBC
    class Database
      def execute_insert_with_returning(conn, sql, opts = {})        
        columns = opts[:key_columns] || ["ROWID"]
        q = "{ call #{sql} returning #{columns.join(',')} into #{columns.collect {|_| '?'}.join(',')} }"
        stmt = conn.prepare_call(q)
        raise "Unable to prepare call for insert" if stmt.nil?

        begin
          columns.each_with_index do |_, index|
            stmt.registerOutParameter(index+1, JavaSQL::Types::VARCHAR)
          end
          return nil if 0 == stmt.executeQuery

          values = (1..columns.count).inject({}) do |memo, index|
            key = columns[index-1].downcase.to_sym rescue nil
            memo[key] = stmt.get_string(index) unless key.nil?
            memo
          end
          values
        ensure
          stmt.close
        end
      end # #execute_insert_with_returning

      alias execute_without_specialized_insert execute
      def execute(sql, opts={}, &block)
        if opts[:type] == :insert
          synchronize(opts[:server]) do |conn|
            execute_insert_with_returning conn, sql, opts
          end
        else
          execute_without_specialized_insert sql, opts, &block
        end
      end # #execute
    end # Database
  end # JDBC
end # Sequel

Я сделал что-то вроде этого, и это работает довольно хорошо.Я думаю, что нам также пришлось переопределить Sequel :: Model, чтобы он передавал первичный ключ в виде opts [: key_columns], но я могу помнить неправильно.

Это немного несущий нагрузку, который получаетработа сделанаБыло бы более элегантно специализировать его для адаптера Oracle JDBC и гарантировать, что весь код обработки ошибок присутствует в исходном операторе execute.Учитывая время, я бы хотел получить что-то лучше и вернуть его в проект Sequel.

0 голосов
/ 24 августа 2011

Адаптер Oracle сиквела не имеет встроенной поддержки подготовленных операторов, поэтому он использует обычный запрос. Если вы можете использовать JRuby, адаптер jdbc имеет встроенную поддержку подготовленных операторов, поэтому он должен просто работать там. Если вы не можете использовать JRuby, вам придется поработать над добавлением встроенной поддержки операторов в адаптер Oracle. У меня нет доступа к установке Oracle, поэтому я не могу протестировать какую-либо поддержку, но я буду рад дать совет, если у вас возникнут проблемы.

0 голосов
/ 24 августа 2011

Способ получения заполненных значений последовательности - через предложение RETURNING оператора INSERT, как я обсуждаю в этом ответе на аналогичный вопрос, касающийся CodeIgniter .

Я не уверен, поддерживает ли базовая версия RoR этот синтаксис, но представляется возможным расширить ActiveRecord для его обработки. Узнать больше .

...