sql >> Database >  >> RDS >> PostgreSQL

Grote objecten van PostgreSQL modelleren in Rails

Als ActiveRecord wordt gebruikt dat bij Rails wordt geleverd met een van zijn adapters, wordt de enige formele toewijzing van het databasetype aan het Rails- of Ruby-type die plaatsvindt, meestal gedefinieerd in de NATIVE_DATABASE_TYPES constante in de adapter die wordt geretourneerd via zijn native_database_types methode. Voor PostgreSQL in Rails 3.2.x is dat in ActiveRecord::ConnectionAdapters::PostgreSQLAdapter dat is hier . Dus voor die adapter verwijst het "binaire" type in Rails naar het "bytea" -type in PG. Voor sommige typen kunt u dat databasetype overschrijven waarnaar het verwijst met behulp van een juweeltje genaamd activerecord-native_db_types_override . Maar we willen grote objecten gebruiken, dus...

Migraties

Zoals Jim Deville opmerkte in de opmerkingen, kunt u de aangepaste getypte kolom in de tabel specificeren zoals:

t.column :some_oid, 'blob_oid', :null => false

Als u nog meer moet doen dat niet-standaard is, kunt u ook een execute("SQL GOES HERE;") gebruiken om de tabel te maken met behulp van rechte SQL. En als u een bestaand verouderd schema of SQL-wijzigingen heeft die buiten de migraties om zijn aangebracht, overweeg dan het gebruik van structure.sql (config.active_record.schema_format = :sql optie in config/application.rb en doe dan:rake db:structure:dump ).

Grote objecten lezen/schrijven/controleren lengte/verwijderen

Gekopieerd met enkele aanpassingen ter verduidelijking, enz. van:https://github.com/diogob/carrierwave-postgresql/blob/v0.1.0/lib/carrierwave/storage/postgresql_lo.rb :

Bijgewerkt :we kunnen, maar hoeven geen begin te maken vóór de lo_read/lo_write/lo_lseek en doen lo_close in zorgen voor blokkering omdat per PG-documentatie "Alle grote objectbeschrijvingen die aan het einde van een transactie open blijven, worden automatisch gesloten." (met dank aan Diogo voor die info)

    require 'pg'

    ...

    def read
      (...).transaction do
        lo = connection.lo_open(identifier)
        content = connection.lo_read(lo, file_length)
        connection.lo_close(lo)
        content
      end
    end

    def write(file)
      (...).transaction do
        lo = connection.lo_open(identifier, ::PG::INV_WRITE)
        size = connection.lo_write(lo, file.read)
        connection.lo_close(lo)
        size
      end
    end

    def delete
      connection.lo_unlink(identifier)
    end

    def file_length
      (...).transaction do
        lo = connection.lo_open(identifier)
        size = connection.lo_lseek(lo, 0, 2)
        connection.lo_close(lo)
        size
      end
    end

In plaats van connection , gebruik de onbewerkte verbinding van het model of de basis, b.v. ActiveRecord::Base.connection.raw_connection (zie dit ).

(...).transaction belt transactie op model of basis, b.v. ActiveRecord::Base.transaction (zie dit ).

identifier is de oid die je ofwel moet doorgeven/instellen of krijgen door gewoon een connection.lo_creat te doen .

Andere voorbeelden/info:

De laatste en enkele antwoorden hier suggereren dat u de opslag van grote bestanden los van de DB zou kunnen overwegen, b.v. zodat u cloudopslag kunt gebruiken. Maar sla alleen de paden/ID's op naar externe bestanden die niet . zijn beheerd door de DB, verliest u de ACID-consistentie (een of meer DB-records kunnen verwijzen naar een of meer bestanden die er niet zijn of een of meer bestanden die niet een of meer bijbehorende records in de database hebben). Een ander argument voor het opslaan van bestanden op het bestandssysteem is dat je bestanden kunt streamen, maar PG large object slaat bestanden op het bestandssysteem op een manier op die wordt beheerd door postgres om zowel ACID-consistentie te garanderen als streaming toe te staan ​​(wat je niet kunt doen met een normale BLOB /Rails binair type). Het hangt er dus gewoon van af; sommigen vinden opslag in aparte opslag met behulp van padverwijzingen een betere optie, en sommigen geven de voorkeur aan ACID-consistentie via grote objecten.

De gemakkelijke manier

Gebruik gewoon CarrierWave en carrierwave-postgresql .




  1. Hoe bewaart u 1/01/1900 3:54:32 uur in MySQL?

  2. Waarden ophalen uit de Oracle DB-tabel in de keuzelijst in c# /wpf

  3. Hoe de insert-query te breken, voordat de trigger mysql wordt ingevoegd

  4. Is een PHP, Python, PostgreSQL-ontwerp geschikt voor een zakelijke toepassing?