View Full Version : [C++][Database] come fare a salvare e recuperare gli oggetti di un programma C++
Perry_Rhodan
11-05-2010, 20:08
Cerco di spiegarmi :fagiano:
Vorrei poter salvare e leggere gli oggetti di un programma c++ che normalmente vengono gestiti in memoria appoggiandomi possibilmente ad un programma di gestione di database sql (cosa mi consigliate? mysql, firebird o ?).
La massa dei dati dovrebbe risiedere sul database su disco, mentre in memoria dovrebbero andare i dati da elaborare, il tutto gestito nel modo più trasparente possibile.
L'ideale sarebbe che nel momento in cui definisco e implemento una classe nel programma sia possibile con pochi semplici passaggi riportarne la struttura sul database in modo che sia semplice salvare gli oggetti o richiamarli alla bisogna realizzando su disco una copia degli oggetti in memoria che mi servono.
Qualcuno cortesemente potrebbe fornirmi spiegazioni o segnalarmi tutorial ed esempi?
o almeno suggerirmi qualche punto da dove partire?
Grazie :)
se non è tanta roba forse è inutile scomodare un DB puoi usare un file XML ;)
praticamente ti serve un sistema di serializzazione per C++ che maschera un database. realizzare un sistema di serializzazione generico per C++ non é facile (per non dire che é semplicemente impossibile) visto che C++ non é un linguaggio riflessivo, cioé non é dotato di reflection.
come al solito mi vengono in mente COM e le tecnologie attive (non so se ADO c'entra qualcosa), ma forse ci sono delle possibilitá piu semplici. attendi qualche parere piu esperto, altrimenti da parte mia hai lo spunto per COM :)
Perry_Rhodan
11-05-2010, 22:34
se non è tanta roba forse è inutile scomodare un DB puoi usare un file XML ;)
Cioè salvare i dati in un file XML, sì è una possibilità, esiste una qualche libreria che renda quanto più possibile trasparente il tutto?
Il database era per avere la possibilità di sfruttare al meglio le funzionalità e l'efficienza del "motore" SQL.
Le funzionalità essenziali che mi servono sono:
Date una o più classi trasferirne la struttura sul DB
salvare oggetti sul DB con le loro varie relazioni
caricare oggetti dal DB ripristinando le corrette relazioni
eliminare oggetti dal DB
la massa dei dati deve stare nel database
in memoria devono stare i dati in elaborazione e gli oggetti temporanei
se il passaggio tra dati su database e dati in memoria fosse gestito in maniare trasparente sarebbe ottimo :mc:
scusate se non sono molto chiaro :)
tomminno
12-05-2010, 07:47
Qualcuno cortesemente potrebbe fornirmi spiegazioni o segnalarmi tutorial ed esempi?
o almeno suggerirmi qualche punto da dove partire?
Grazie :)
Una libreria che fa più o meno quello che chiedi è SOCI (http://soci.sourceforge.net/)
I database supportati sono praticamente tutti quelli in circolazione.
tomminno
12-05-2010, 07:53
Le funzionalità essenziali che mi servono sono:
Date una o più classi trasferirne la struttura sul DB
salvare oggetti sul DB con le loro varie relazioni
caricare oggetti dal DB ripristinando le corrette relazioni
eliminare oggetti dal DB
Per questo ti servirebbe più un ORM (Linq, Hibernate,...).
Non mi risultano esistere ORM in C++.
Altrimenti usi i tradizionali strumenti messi a disposizione dai database: stored procedure e viste.
banryu79
12-05-2010, 08:21
Per questo ti servirebbe più un ORM (Linq, Hibernate,...).
Non mi risultano esistere ORM in C++.
Altrimenti usi i tradizionali strumenti messi a disposizione dai database: stored procedure e viste.
Sì.
Ma se non deve gestire vagonate di record forse potrebbe evitare l'ORM appoggiandosi direttamente ad un database ad oggetti, invece che relazionale.
Oppure provare ad usare qualcosa di diverso come un Prevalent System (se i requisiti lo permettono).
In entrambi i casi non so quali datbase/librerie esitano allo scopo (per C++).
@EDIT: la relativa voce su wikipedia (http://en.wikipedia.org/wiki/System_Prevalence) (sperando che nessuno resti disgustato :asd: ).
Perry_Rhodan
12-05-2010, 12:38
praticamente ti serve un sistema di serializzazione per C++ che maschera un database. realizzare un sistema di serializzazione generico per C++ non é facile (per non dire che é semplicemente impossibile) visto che C++ non é un linguaggio riflessivo, cioé non é dotato di reflection.
come al solito mi vengono in mente COM e le tecnologie attive (non so se ADO c'entra qualcosa), ma forse ci sono delle possibilitá piu semplici. attendi qualche parere piu esperto, altrimenti da parte mia hai lo spunto per COM :)
Sì direi che hai sintetizzato bene quello che ho in mente ;)
E Ricorrendo ad altri linguaggi come Python o Java?
Dici che dovrebbero essere più adatti, questi almeno sono linguaggi riflessivi?
Vorrei però rimanere sul C++ che conosco meglio (Molto Molto relativamente :stordita: ), ritengo più efficiente anche se più ostico e IMHO dovrebbe essere in grado di fare qualunque cosa, almeno in linea teorica.
Grazie per gli spunti interessanti :)
Perry_Rhodan
12-05-2010, 12:49
Sì.
Ma se non deve gestire vagonate di record forse potrebbe evitare l'ORM appoggiandosi direttamente ad un database ad oggetti, invece che relazionale.
Oppure provare ad usare qualcosa di diverso come un Prevalent System (se i requisiti lo permettono).
In entrambi i casi non so quali datbase/librerie esitano allo scopo (per C++).
@EDIT: la relativa voce su wikipedia (http://en.wikipedia.org/wiki/System_Prevalence) (sperando che nessuno resti disgustato :asd: ).
Vorrei che il numero di record gestibile sia ininfluente (da pochi record a "vagonate"), ovviamente se i record sono pochi si può fare tutto in RAM riducendo il problema a definire la struttura e a salvare/richiamare i dati, ma io penso ad un sistema semplice che permetta di caricare in memoria solo il sottinsieme di dati necessari alle elaborazioni lasciando l'insieme principale dei dati su disco.
La reflection non c'è in c++, ma volendo un approccio valido alla serializzazione si può ottenere con typeid: http://en.wikipedia.org/wiki/Typeid
Quindi la serializzazione è abbastanza facile da realizzare, sia implementandola tramite una classe base astratta, sia utilizzando librerie esterne (le boost hanno la serializzazione).
In alternativa si può usare un db su file, come sqlite, che si può integrare facilmente e con praticamente nessuna dipendenza.
Vorrei però rimanere sul C++ che conosco meglio (Molto Molto relativamente :stordita: ), ritengo più efficiente anche se più ostico e IMHO dovrebbe essere in grado di fare qualunque cosa, almeno in linea teorica.
Grazie per gli spunti interessanti :)
...si puoi potenzialmente fare ogni cosa...ma hai il tempo e le competenze per farlo?...con altri linguaggi ottieni gli stessi risultati in tempi piu' brevi e senza dannarti troppo...
...ciao Andrea...
senza dannarti troppo...
Ma nemmeno tanto...visto che esistono già librerie che lo fanno e visto che per studiare un sistema di serializzazione in C++ ci vogliano 10 minuti.
Ma nemmeno tanto...visto che esistono già librerie che lo fanno e visto che per studiare un sistema di serializzazione in C++ ci vogliano 10 minuti.
...si ma con un ORM si starebbe già preoccupando dei soli oggettoni...
...ciao Andrea...
Perry_Rhodan
12-05-2010, 19:38
Una libreria che fa più o meno quello che chiedi è SOCI (http://soci.sourceforge.net/)
I database supportati sono praticamente tutti quelli in circolazione.
SOCI mi sembra interessante , magari insieme alle boost, anche se non è esttamente quello che avevo in mente.
Sì in effetti quello che mi servirebbe è un ORM tipo hibernate a cui ho dato un'occhiata, peccato sia per java.
Esiste qualcosa di simile ad hibernate in C++ ?????
SOCI mi sembra interessante
Non ti basta da solo, serve anche un DBMS...ed i DBMS supportati sono
* Oracle
* PostgreSQL
* MySQL
Quindi DBMS molto corposi e che necessitano di una installazione.
Ribadisco quindi che la soluzione è farti la serializzazione o a manina o tramite boost. In alternativa sqlite come database embedded.
tomminno
12-05-2010, 21:04
Non ti basta da solo, serve anche un DBMS...ed i DBMS supportati sono
* Oracle
* PostgreSQL
* MySQL
Quindi DBMS molto corposi e che necessitano di una installazione.
Ribadisco quindi che la soluzione è farti la serializzazione o a manina o tramite boost. In alternativa sqlite come database embedded.
Ehm funziona anche con Sqlite, SqlServer (odbc), Firebird, Oledb. Puoi cambiare il database solo modificando la stringa di connessione.
tomminno
12-05-2010, 21:10
Esiste qualcosa di simile ad hibernate in C++ ?????
Purtroppo no.
Se c'è un settore dove C++ è molto indietro è proprio quello dell'interfaccia verso i database e non credo che ci saranno mai evoluzioni in tal senso, ormai il treno è perso in favore di linguaggi come Java e C#.
Ehm funziona anche con Sqlite, SqlServer (odbc), Firebird, Oledb. Puoi cambiare il database solo modificando la stringa di connessione.
Non avevo visto che la versione CVS supporta anche quelli, ovviamente però si tratta della versione unstable...
tomminno
13-05-2010, 08:26
Non avevo visto che la versione CVS supporta anche quelli, ovviamente però si tratta della versione unstable...
Io l'ho usato tranquillamente sia con Sqlite che con SqlServer.
Con Sqlite non ho trovato limitazioni anche perchè se manca qualche funzionalità è possibile accedere direttamente alle api del backend, per quanto riguarda SqlServer credo che sia dovuto al parziale supporto alle stored procedure, supporto facilmente realizzabile aggiungendo 2 elementi ad un enum e gestendoli opportunamente nel backend odbc, ho contattato il mantainer del progetto per proporgli la mia modifica, ma non ho avuto risposta.
Ho usato intensivamente il backend odbc e non ho riscontrato problemi, con questa libreria riesco a coprire il 100% delle mie casistiche di utilizzo dei db con prestazioni sorprendenti visto che nelle prove che ho fatto è risultata pure più veloce del TDS implementato in ADO.NET (non si diceva che odbc era obsoleto e lento?)
La reflection non c'è in c++, ma volendo un approccio valido alla serializzazione si può ottenere con typeid: http://en.wikipedia.org/wiki/Typeid
Quindi la serializzazione è abbastanza facile da realizzare, sia implementandola tramite una classe base astratta, sia utilizzando librerie esterne (le boost hanno la serializzazione). ammettiamo di poter salvare su file un dato (restituito da typeid) che permetta poi, in fase di lettura, di identificare il tipo dell'oggetto; ma il salvataggio come lo facciamo? castiamo brutalmente a void* il puntatore all'oggetto e scriviamo sul file ció a cui punta per la dimensione indicata da sizeof? e se l'oggetto da salvare contiene riferimenti o puntatori o puntatori a puntatori ad altri oggetti che facciamo?
inoltre, in fase di lettura, una volta che abbiamo letto il nome del tipo dell'oggetto salvato o che siamo riusciti a ricavarne l'oggetto std::type_info che ci si fa? come facciamo ad istanziare quel tipo?
altra cosa: nel caso in cui scrivessimo l'oggetto su file scrivendo brutalmente i bytes contenuti nella sua area di memoria (che ha dimensioni indicate da sizeof) scriveremmo anche la vtable; e chi mi dice che alla prossima esecuzione del programma i puntatori della vtable saranno gli stessi? il modulo eseguibile potrebbe essere stato rilocato diversamente, ad esempio perché é una DLL caricata dinamicamente o perché il base address é randomizzato per motivi di sicurezza.
Una cosa alla volta... Come si fa ad istanziare ? Quello è facile...
Comunque bisogna conoscere la struttura del file... Una volta che la si conosce basta istanziare l'oggetto tramite un factory method.
Riguardo a puntatori e reference, basta descriverne la serializzazione, così come si fa per il costruttore di copia...
Una cosa alla volta... Come si fa ad istanziare ? Quello è facile...
Comunque bisogna conoscere la struttura del file... Una volta che la si conosce basta istanziare l'oggetto tramite un factory method. d'accordo, questo ci puó stare; piu specificamente diciamo che si potrebbe usare un oggetto std::map dove le chiavi sono std::string contenenti i nomi delle classi e i valori sono chiusure che istanziano l'oggetto giusto. resterebbe il problema di come inizializzare questa mappa in una maniera comoda per il programmatore finale, dove "comoda" significa che sarebbe da evitare che il programmatore finale sia costretto a scrivere manualmente una entry per ogni classe serializzabile perché nel fare questo potrebbe commettere errori (potrebbe dimenticarsi una classe oppure lasciarci delle entries di troppo se durante un refactoring elimina una classe e si dimentica di eliminare la entry corrispondente). quindi ci vorrebbe ancora un po' di lavoro, peró in fondo ho riflettuto sulla questione e ho concluso che non sarebbe neanche strettamente necessario istanziare l'oggetto con un costruttore se in fase di lettura si leggessero brutalmente i bytes. ma la cosa sarebbe orribile perché oltre ad essere molto á la C lascerebbe apertissimo il problema di cui parlo sotto.
Riguardo a puntatori e reference, basta descriverne la serializzazione, così come si fa per il costruttore di copia... la ricorsivitá della serializzazione che si propaga automaticamente anche a oggetti (serializzabili) riferiti/puntati é un aspetto assolutamente fondamentale di un buon sistema di serializzazione. non ho capito bene la soluzione che proponi ma sembra che tu stia trascurando l'avverbio "automaticamente": chi é che deve "descrivere la serializzazione" di puntatori e riferimenti? non il programmatore finale si spera. e comunque resta il problema della vtable.
Ovviamente il programmatore finale... Non c'è alternativa. L'ho scritto che non è equivalente alla reflection...
Ovviamente il programmatore finale... Non c'è alternativa. L'ho scritto che non è equivalente alla reflection... ribadisco, resta il problema della vtable.
ribadisco, resta il problema della vtable.
Ci dovrei pensare, ma non mi sembra che ci siano problemi...
Noi si fa come ha detto cionci, ma evitando accuratamente typeid (siamo puristi :D ).
Ogni oggetto serializzabile o è di tipo "finale" e viene creato direttamente con new, oppure fornisce il nome della factory che andrà cercata in fase di deserialize per ricrearlo.
Per i dettagli dell'oggetto stesso si passa il resto dello stream al nuovo oggetto che estrae polimorficamente i dati e restituisce lo stream del prossimo oggetto.
Il problemi sono che la deserializzazione e la serializzazione non possono comunque essere fatte automaticamente (anche perchè non avrebbe senso salvare tutto di un oggetto, altrimenti bastava un dump della memoria), hanno dentro un bel pò di hardcoding e sono tediose.
In più bisogna creare tutte le factories col nome giusto prima di deserializzare il tutto altrimenti non va.
Tuttavia non credo proprio che col C++ si possa fare di meglio, quindi ci si adatta :asd:
Tuttavia non credo proprio che col C++ si possa fare di meglio, quindi ci si adatta :asd: per forza che non si puó, non é un linguaggio riflessivo; la serializzazione in C++ non esiste.
per forza che non si puó, non é un linguaggio riflessivo; la serializzazione in C++ non esiste.
Dipende che intendi per serializzazione. La serializzazione automatica non esiste, ma la serializzazione in una ambiente controllato esiste.
Perry_Rhodan
14-05-2010, 23:50
grazie per gli spunti interessanti, in effetti temo che la questione sia un "tantinello" più complessa di quanto pensavo :D
penso che ridarò un'occhiata a python e java ;)
conoscete qualche tutorial o testo disponibile in rete che tratti dei metodi di salvataggio e rilettura dei dati in generale e magari in riferimento a C++ python e java?
Voi in genere come fate?
file testo, file binario, file csv, XML, database, altro?
Perry_Rhodan
19-05-2010, 19:39
grazie per gli spunti interessanti, in effetti temo che la questione sia un "tantinello" più complessa di quanto pensavo :D
penso che ridarò un'occhiata a python e java ;)
conoscete qualche tutorial o testo disponibile in rete che tratti dei metodi di salvataggio e rilettura dei dati in generale e magari in riferimento a C++ python e java?
Voi in genere come fate?
file testo, file binario, file csv, XML, database, altro?
scusate l'Upppp! :)
Qualche altro spunto?
scusate l'Upppp! :)
Qualche altro spunto? in generale, quando devo serializzare un oggetto, se devo farlo in Java o C# é banale, invece per il C++ mi vedo costretto ad inventarmi un formato. non mi capita molto spesso a dire la veritá, comunque scelgo tra formato testuale e formato binario a seconda delle esigenze; per esempio se l'utente deve poter modificare a mano, il formato testuale é d'obbligo, mentre se mi sta a cuore ridurre al minimo le dimensioni procedo senza indugio col formato binario.
tomminno
19-05-2010, 21:41
in generale, quando devo serializzare un oggetto, se devo farlo in Java o C# é banale, invece per il C++ mi vedo costretto ad inventarmi un formato. non mi capita molto spesso a dire la veritá, comunque scelgo tra formato testuale e formato binario a seconda delle esigenze; per esempio se l'utente deve poter modificare a mano, il formato testuale é d'obbligo, mentre se mi sta a cuore ridurre al minimo le dimensioni procedo senza indugio col formato binario.
In caso di necessità non c'è bisogno di reinventare la ruota, c'è boost::serialization che implementa una serializzazione completa e pure il versioning. Inoltre è sempre possibile aggiungere la serializzazione anche a posteriori senza modificare il codice della classe.
Un'altra modalità di "serializzazione" che ho usato in C++ è tramite XML e la libreria Xsd, più che altro in caso di protocolli basati su xml per cui era facile definire uno schema, la libreria si occupa automaticamente della serializzazione e deserializzazione (xml) da e verso una stringa o uno stream.
O ancora gsoap in caso di comunicazioni soap.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.