PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Làm cách nào để truy cập giá trị mặc định của cột Postgres bằng ActiveRecord?

Khi ActiveRecord cần biết về một bảng, nó thực hiện một truy vấn tương tự như information_schema của bạn nhưng AR sẽ đi qua Bảng hệ thống dành riêng cho PostgreSQL thay vào đó:

  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

Tìm kiếm trong Nguồn bộ điều hợp PostgreSQL cho "regclass" và bạn sẽ thấy một số truy vấn khác mà AR sẽ sử dụng để tìm ra cấu trúc của bảng.

pg_get_expr lệnh gọi trong truy vấn trên là nơi bắt nguồn giá trị mặc định của cột.

Kết quả của truy vấn đó, dù ít hay nhiều, truy cập vào PostgreSQLColumn.new :

Các cột
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 phương thức khởi tạo sẽ sử dụng extract_value_from_default để Ruby-ify làm mặc định; phần cuối của công tắc trong extract_value_from_default là thú vị ở đây:

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

Vì vậy, nếu giá trị mặc định được liên kết với một chuỗi (mà một id cột trong PostgreSQL sẽ là), sau đó mặc định sẽ xuất hiện từ cơ sở dữ liệu dưới dạng một lệnh gọi hàm tương tự như sau:

nextval('models_id_seq'::regclass)

Điều đó sẽ kết thúc trong else ở trên nhánh và column.default.nil? sẽ đúng.

Đối với một id cột này không phải là vấn đề, AR hy vọng cơ sở dữ liệu cung cấp các giá trị cho id nên nó không quan tâm giá trị mặc định là gì.

Đây là một vấn đề lớn nếu mặc định của cột là thứ mà AR không hiểu, hãy nói một hàm như vậy dưới dạng md5 (random () ::text) . Vấn đề là AR sẽ khởi tạo tất cả các thuộc tính thành giá trị mặc định của chúng - dưới dạng Model.columns nhìn thấy chúng, không phải khi cơ sở dữ liệu nhìn thấy chúng - khi bạn nói Model.new . Ví dụ:trong bảng điều khiển, bạn sẽ thấy những thứ như sau:

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

Vì vậy, nếu def_is_osystem thực sự sử dụng một lệnh gọi hàm làm giá trị mặc định của nó, AR sẽ bỏ qua điều đó và cố gắng chèn NULL làm giá trị của cột đó. NULL đó sẽ ngăn không cho giá trị mặc định được sử dụng và bạn sẽ kết thúc với một mớ hỗn độn khó hiểu. Mặc dù vậy, các mặc định mà AR có thể hiểu (chẳng hạn như chuỗi và số) hoạt động tốt.

Kết quả là bạn không thể thực sự sử dụng các giá trị cột mặc định không tầm thường với ActiveRecord, nếu bạn muốn một giá trị không tầm thường thì bạn phải thực hiện trong Ruby thông qua một trong các lệnh gọi lại ActiveRecord (chẳng hạn như before_create ).

IMO Sẽ tốt hơn nhiều nếu AR để lại các giá trị mặc định cho cơ sở dữ liệu nếu nó không hiểu chúng:để chúng ra khỏi CHÈN hoặc sử dụng DEFAULT trong các GIÁ TRỊ sẽ tạo ra kết quả tốt hơn nhiều; Tất nhiên AR sẽ phải tải lại các đối tượng mới được tạo từ cơ sở dữ liệu để có được tất cả các giá trị mặc định thích hợp nhưng bạn chỉ cần tải lại nếu có các giá trị mặc định mà AR không hiểu. Nếu else trong extract_value_from_default đã sử dụng cờ đặc biệt "Tôi không biết điều này có nghĩa là gì" thay vì nil thì điều kiện "Tôi cần tải lại đối tượng này sau lần lưu đầu tiên" sẽ rất khó phát hiện và bạn chỉ tải lại khi cần thiết.

Ở trên là PostgreSQL cụ thể nhưng quy trình phải tương tự đối với các cơ sở dữ liệu khác; tuy nhiên, tôi không đảm bảo.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm thế nào để ghi lại sự thay đổi dữ liệu trong postgresql?

  2. Đặt hàng theo ngày ASC với dữ liệu mùa xuân

  3. Truy vấn SQL để lấy hàng gần đây nhất cho mỗi trường hợp của một khóa nhất định

  4. Điền dữ liệu ngẫu nhiên từ một bảng khác

  5. gói không thành công - Không thể tìm thấy thư viện máy khách PostgreSQL (libpq)