PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Jak mogę uzyskać dostęp do domyślnej wartości kolumny Postgres za pomocą ActiveRecord?

Kiedy ActiveRecord potrzebuje wiedzieć o tabeli, wykonuje zapytanie podobne do twojego schemat_informacji zapytanie, ale AR przejdzie przez Tabele systemowe specyficzne dla PostgreSQL zamiast tego:

  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

Wyszukaj źródło adaptera PostgreSQL dla "regclass", a zobaczysz kilka innych zapytań, których AR użyje do ustalenia struktury tabeli.

pg_get_expr wywołanie w powyższym zapytaniu to miejsce, z którego pochodzi domyślna wartość kolumny.

Wyniki tego zapytania idą mniej więcej prosto do 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

Kolumna PostgreSQL konstruktor użyje extract_value_from_default do Ruby-ify domyślnie; koniec przełącznik w extract_value_from_default jest tu interesujące:

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

Więc jeśli domyślna wartość jest powiązana z sekwencją (którą jest id kolumna w PostgreSQL), wtedy domyślnie wyjdzie z bazy danych jako wywołanie funkcji podobne do tego:

nextval('models_id_seq'::regclass)

To skończy się w powyższym innym branch i kolumna.default.nil? będzie prawdą.

Dla id kolumna to nie jest problem, AR oczekuje, że baza danych dostarczy wartości dla id kolumn, więc nie obchodzi go, jaka jest wartość domyślna.

Jest to duży problem, jeśli domyślną wartością kolumny jest coś, czego AR nie rozumie, powiedz wywołanie takiej funkcji jako md5(random()::text) . Problem polega na tym, że AR zainicjuje wszystkie atrybuty do ich wartości domyślnych – jako Model.columns widzi je, a nie tak, jak widzi je baza danych – kiedy mówisz Model.new . Na przykład w konsoli zobaczysz takie rzeczy:

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

Więc jeśli def_is_function faktycznie używa wywołania funkcji jako wartości domyślnej, AR zignoruje to i spróbuje wstawić NULL jako wartość tej kolumny. Ta wartość NULL zapobiegnie użyciu wartości domyślnej i skończysz z mylącym bałaganem. Domyślne wartości, które AR może zrozumieć (takie jak ciągi i liczby) działają dobrze.

Rezultat jest taki, że tak naprawdę nie możesz używać nietrywialnych domyślnych wartości kolumn z ActiveRecord, jeśli chcesz nietrywialną wartość, musisz to zrobić w Rubim za pomocą jednego z wywołań zwrotnych ActiveRecord (takich jak before_create ).

IMO byłoby znacznie lepiej, gdyby AR pozostawił wartości domyślne w bazie danych, jeśli ich nie rozumiał:pozostawienie ich poza WSTAWKĄ lub użycie DOMYŚLNYCH w WARTOŚCIACH dałoby znacznie lepsze wyniki; AR musiałby oczywiście ponownie załadować nowo utworzone obiekty z bazy danych, aby uzyskać wszystkie prawidłowe wartości domyślne, ale ponowne wczytanie byłoby potrzebne tylko wtedy, gdy istnieją wartości domyślne, których AR nie rozumie. Jeśli inny w extract_value_from_default użył specjalnej flagi „Nie wiem, co to znaczy” zamiast nil wtedy warunek „Muszę ponownie załadować ten obiekt po pierwszym zapisaniu” byłby trywialny do wykrycia i ładowałbyś go ponownie tylko wtedy, gdy jest to konieczne.

Powyższe jest specyficzne dla PostgreSQL, ale proces powinien być podobny dla innych baz danych; jednak nie udzielam żadnych gwarancji.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Dlaczego rails 5 dodaje metodę nextval w pliku schematu?

  2. Struktury kontrolne PL/pgSQL dla list / tablic

  3. Transakcje nie działają dla mojej bazy danych MySQL

  4. Sequelize Error:Relacja nie istnieje

  5. Łączenie dwóch oddzielnych zapytań w postgresql ...query... (możliwe lub niemożliwe)