PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Bagaimana saya bisa mengakses nilai default kolom Postgres menggunakan ActiveRecord?

Ketika ActiveRecord perlu mengetahui tentang sebuah tabel, ia melakukan kueri yang mirip dengan information_schema Anda permintaan tetapi AR akan melalui Tabel sistem khusus PostgreSQL sebagai gantinya:

  SELECT a.attname, format_type(a.atttypid, a.atttypmod),
         pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
    FROM pg_attribute a LEFT JOIN pg_attrdef d
      ON a.attrelid = d.adrelid AND a.attnum = d.adnum
   WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
     AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum

Telusuri sumber adaptor PostgreSQL untuk "regclass" dan Anda akan melihat beberapa kueri lain yang akan digunakan AR untuk mengetahui struktur tabel.

pg_get_expr panggilan dalam kueri di atas adalah asal nilai default kolom.

Hasil kueri itu, kurang lebih, langsung ke PostgreSQLColumn.new :

def columns(table_name, name = nil)
  # Limit, precision, and scale are all handled by the superclass.
  column_definitions(table_name).collect do |column_name, type, default, notnull|
    PostgreSQLColumn.new(column_name, default, type, notnull == 'f')
  end
end

PostgreSQLColumn konstruktor akan menggunakan extract_value_from_default untuk Ruby-ify default; akhir switch di extract_value_from_default menarik di sini:

else
  # Anything else is blank, some user type, or some function
  # and we can't know the value of that, so return nil.
  nil

Jadi jika nilai default terikat ke urutan (yang merupakan id kolom di PostgreSQL akan menjadi), maka default akan keluar dari database sebagai pemanggilan fungsi mirip dengan ini:

nextval('models_id_seq'::regclass)

Itu akan berakhir di else di atas cabang dan column.default.nil? akan menjadi kenyataan.

Untuk id kolom ini bukan masalah, AR mengharapkan database menyediakan nilai untuk id kolom sehingga tidak peduli apa nilai defaultnya.

Ini adalah masalah besar jika default kolom adalah sesuatu yang AR tidak mengerti, katakan panggilan fungsi seperti itu sebagai md5(random()::text) . Masalahnya adalah AR akan menginisialisasi semua atribut ke nilai defaultnya – sebagai Model.columns melihatnya, bukan seperti yang dilihat database – saat Anda mengucapkan Model.new . Misalnya, di konsol Anda akan melihat hal-hal seperti ini:

 > Model.new
=> #<Model id: nil, def_is_function: nil, def_is_zero: 0>

Jadi jika def_is_function sebenarnya menggunakan panggilan fungsi sebagai nilai defaultnya, AR akan mengabaikannya dan mencoba memasukkan NULL sebagai nilai kolom itu. NULL itu akan mencegah nilai default digunakan dan Anda akan berakhir dengan kekacauan yang membingungkan. Default yang dapat dipahami AR (seperti string dan angka) berfungsi dengan baik.

Hasilnya adalah Anda tidak dapat benar-benar menggunakan nilai kolom default non-trivial dengan ActiveRecord, jika Anda menginginkan nilai non-trivial maka Anda harus melakukannya di Ruby melalui salah satu callback ActiveRecord (seperti before_create ).

IMO akan jauh lebih baik jika AR meninggalkan nilai default ke database jika tidak memahaminya:meninggalkannya dari INSERT atau menggunakan DEFAULT dalam VALUES akan menghasilkan hasil yang jauh lebih baik; AR tentu saja harus memuat ulang objek yang baru dibuat dari database untuk mendapatkan semua default yang tepat, tetapi Anda hanya perlu memuat ulang jika ada default yang tidak dipahami AR. Jika else di extract_value_from_default menggunakan tanda khusus "Saya tidak tahu apa artinya ini" alih-alih nil maka kondisi "Saya perlu memuat ulang objek ini setelah penyimpanan pertama" akan mudah dideteksi dan Anda hanya akan memuat ulang jika diperlukan.

Di atas adalah khusus PostgreSQL tetapi prosesnya harus serupa untuk database lain; namun, saya tidak memberikan jaminan.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana saya bisa mempercepat operasi pembaruan/penggantian di PostgreSQL?

  2. Mengurai pemutakhiran PostgreSQL

  3. Bagaimana cara menyalin data dari satu tabel ke tabel lain di postgres menggunakan perintah salin

  4. UPDATE/INSERT berdasarkan jika ada baris

  5. Ubah prosedur tersimpan SQL Server menjadi prosedur tersimpan PostgreSQL