Newsgroup: it.comp.lang.c++
Titolo: Rappresentare una tabella

Secondo voi, qual'è il metodo "migliore" (nel senso del miglior mix tra
efficienza, semplicità di manutenzione e correttezza stilistica) per
rappresentare una tabella di database in un programma C++? Sapendo che il
numero di campi è variabile...io avevo pensato
1) un vector di map in cui ogni elemento del vector rappresenta una riga
   della tabella e nella map posso associare ai nomi dei campi i valori
   rispettivi. Questa è la soluzione che mi pare più "bella",ma ho paura 
   che sia troppo dispendiosa in quanto a risorse e lenta.
2) un semplicissimo array bidimensionale, velocissimo e che rappresenta
   perfettamente la struttura bidimensionale della tabella. Questa
   probabilmente è la soluzione più veloce, ma poco flessibile, se la
   tabella dovesse aggiungere una colonna sarei costretto a fare un
   casino, per non parlare dell'aggiunta di una nuova riga...e in più non
   mi pare molto elegante
3) una via di mezzo tra le due soluzioni
4) un vostro consiglio / suggerimento! :-)
Grazie del tempo perso a leggere...se poi qualcuno risponde grazie 4
volte!:-)

    che sia troppo dispendiosa in quanto a risorse e lenta.
Che ne pensi di una std::map < Record >, uno std::vector < Record > o
una std::list < Record > a seconda del tipo di operazioni più frequenti,
dove Record è la classe che rappresenta il record del tuo database?
EMG
--
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg

 
infatti, ho creato un tipo Rec che rappresenta il record mediante una map
(mi interessava avere il nome dei campi come indice) e poi un vector di
Rec...quello che mi preoccupa è la velocità


 numero di campi è variabile...io avevo pensato
Mia proposta: tanti puntatori a vettori di vettori quanti sono i tipi
elementari. Accesso basato sul tipo e sull'indice del campo e della riga.
Indice del campo deducibile tramite una chiamata ad-hoc per rendere tale
costo costante.
Ciao!
Azathot



Grazie della proposta, ma mi sembra troppo macchinosa.

 Grazie della proposta, ma mi sembra troppo macchinosa.
Hai detto che la volevi efficiente ed elegante. Questa è entrambe. Non hai
mai specificato che la volevi semplice.
ciao!
Azathot

 >>    paura che sia troppo dispendiosa in quanto a risorse e lenta.
io  ho costruito una cosa del genere.
Se utilizzi gli ODBC, hai la possibilità di poter gestire il campo della
tabella indipendentemente dal tipo che quel campo contiene, è questo ti è
sufficente, in quanto ti basta costruirti una classe che gestisce il campo,
ed il gioco è fatto.
ad esempio
class CCampo...
typedef deque <CCampo *> RECORD // perché il numero dei campi è sconosciuto
typedef map<int, RECORD *, less<int>() > TABELLA // dove int, è il valore
dell'indice della tabella
--
Ciao.
Maurizio
P.S.: eliminare _!NO$PAM! per rispodere in privato

 numero di campi è variabile...io avevo pensato
[...]
Dipende da come effettivamente vuoi utilizzare questa
rappresentazione. Senza questa informazione mi pare inutile sparare
idee a casaccio.
Ciao,
Nicola



Non ho detto che non è semplice, ma è macchinosa, nel senso difficile da
gestire e manutenere nel caso in cui ci sia bisogno di aggiungere
qualcosa.
Grazie comunque!!

 qualcosa.
Cosa devi aggiungere, scusa? Per ogni tipo rappresentabile inserisci un
puntatore ad un vettore di vettori (magari STL). Per ogni campo di quel
tipo assegni un elemento (un vettore) nel vettore. Per ogni elemento
dimensioni il vettore quanti sono i record.
Non vedo la difficoltà di manutenzione e di gestione. In quanto a
macchinosità, il problema, devi ammetterlo, è macchinoso.
Azathot



Già...in effetti il C++ non è proprio il linguaggio più adatto per la
gestione di database...
Cmq, ad esempio aggiungere un nuovo tipo, o meglio, sostituire i tipi
prefediniti con altri tipi più adatti alle esigenze non è proprio una
passeggiata col metodo che mi suggerisci tu...a meno che non mi sfugga
qualcosa...
Devo valutare bene i pro e i contro di ogni approccio, comunque molte
grazie per l'interessamento e per il consiglio!
Yes

 qualcosa...
Non confondere i tipi astratti con i tipi concreti.
Ciao!
Azathot

 Azathot
 
Sai com'č, al giorno d'oggi non si capisce piů niente, astratto,
concreto...forse č meglio se vado su it.scienze.filosofia!:-)

 gestione di database...
Dici?
http://www.sqlapi.com/
http://dtemplatelib.sourceforge.net/index.htm
http://members.fortunecity.com/skuchin/home.htm
http://pqxx.tk/
Ciao,
Nicola



Interessanti come links, grazie!

 rappresentare una tabella di database in un programma C++?
[cut]
beh, dipende da cosa ci devi fare; nel modello relazionale una tabella e` 
definita come "insieme di record", quindi un buon punto di partenza 
potrebbe essere std::set<Record>, dove Record e` una classe specifica. 
Pero` nel tuo caso specifico potresti essere interessato a mantenere 
l'ordine dei record, per cui vector o list potrebbero essere migliori di 
set.
Poi bisogna anche discutere l'implementazione di Record: nel modello 
relazionale un record e` una tupla di valori, per cui 
std::vector<Value*> potrebbe andare bene, ma anche in questo caso 
bisogna vedere cosa ci devi fare; ad esempio, dato un record come fai ad 
ottenere il valore del campo "Nome"?
Provo a stendere un primo e banale design (il codice non e` completo, 
serve solo come schema):
using namespace std;
// Rappresenta un valore memorizzato nel database
class Value
{
     // ....
};
// mappa tra nome di campo e posizione all'interno della tupla
class TableHeader {
public:
      size_t fieldIndex(string fieldName);
private:
      map<string, int> names;
};
class Record {
      // restituisce il valore di uno specifico campo
      Value& operator[](string fieldName);
private:
      vector<Value*> values;
      TableHeader* header;
};
class Table {
      // iterano sui record
      table_iterator begin();
      table_iterator end();
private:
      TableHeader header;
      vector<Record> records;
};
Ogni record ha un puntatore all'header della tabella: in questo modo 
esiste un solo header che contiene i nomi dei campi ed e` condiviso da 
tutti i record.
"A naso" mi sembra che questa struttura sia abbastanza flessibile ed 
efficiente, pero` bisogna vedere quali sono le tue necessita`; ad 
esempio:
- il numero di campi e` fisso o puo` variare? Varia a run-time o 
compile-time?
- i record sono ottenuti da un database? Devi fare il fetch tutto assieme 
o lo devi fare in maniera incrementale?
- devi poter modificare i record o ti basta leggerli?
- devi effettuare delle ricerche sulla tabella? Ad esempio anziche` usare 
un vector<Record> potresti utilizzare un map<PrimaryKey, Record>; oppure 
usare un vector<Record> e diversi indici del tipo map<Key, Index>.
ciao Anto
-- 
"Computer science is not about computers any more than astronomy
is about telescopes." -- EW Dijkstra

potrebbe essere std::set<Record>, dove Record e` una classe specifica. 
Hmmm... non sono molto convinto di questo approccio.
SQL, per esempio, lavora prevalentemente sulle colonne, quindi
congelare la struttura in insiemi di righe può essere svantaggioso.
Che ne dici ?
-- 
Andrea Laforgia
Gioca a Tetris !
http://www.geocities.com/andrealaforgia/downloads.html

 Che ne dici ?
non capisco cosa intendi con "lavorare prevalentemente sulle colonne"; in 
genere in un db le colonne (i campi) di una tabella sono fisse mentre le 
righe (i record) sono ovviamente variabili. D'altronde il modello 
relazionale definisce una tabella (aka relazione) proprio come "insieme 
di tuple", dove tupla e` quello che comunemente chiamiamo record.
Ho l'impressione che ci stiamo capendo male...


 ciao Anto
Allora...io ho bisogno di implementare una funzione che esegua una query
SQL e ritorni i valori in una struttura dati. Naturalmente il problema è
definire una tale struttura. Io a priori non conosco la query, quindi non
conosco le colonne che mi ritorneranno. La struttura del record, perciò,
non può essere fissa. Inoltre sarebbe una grande comodità poter
utilizzare i nomi dei campi invece di indici o altro. Per cui avevo
pensato a definire Record come map<string, myValue>, dove myValue è un
tipo "variante", che può contenere tutti i tipi fondamentali del DB, che
tra l'altro già ho costruito. A questo punto, avrei pensato a definire un
vector di Record in modo da avere rappresentata la tabella in modo molto
fedele all'originale. Però ho dei problemi pratici ad implementarla, non
vorrei incapsulare tutto in classi. Posso fare una cosa del genere?
typedef std::map<string, MyVar*> Record ;
typedef std::vector<Record *> Table;
Come posso fare una cosa simile, ma fare in modo da accedere con qualcosa
tipo:
Table t;
cout<<t[0]["CODICE"]<<endl;

tupla e` quello che comunemente chiamiamo record.
Il modello relazionale definisce una relazione (la "tabella" č solo
una rappresentazione) come un sottoinsieme del prodotto dei domini
della relazione.  Il problema č se, per lavorare, č necessario avere,
a propria volta, un sottoinsieme di questa relazione.


 utilizzare i nomi dei campi invece di indici o altro.
Che ne pensi di seguire il modello ADO (o gerarchie analoghe)? Forse è
inutile scervellarsi a reinventare la ruota.
EMG


 fa, non vengono richieste _tutte_ le colonne, ma un set limitato.
[cut]
ok, ora ho capito quello che intendi e sono d'accordo con te; infatti se 
guardi l'insieme di classi che avevo postato qualche giorno fa ti 
accorgi che l'insieme delle colonne non deve essere prefissato: quando a 
run-time crei un oggetto Table devi anche specificare il numero e i nomi 
delle colonne, quindi e` possibile utilizzare la stessa classe anche per 
query molto diverse tra loro.


 cout<<t[0]["CODICE"]<<endl;
ovviamente non e` possibile fare direttamente quel che dici tu; ci sono 
due modi per rendere quel codice compilabile:
1) usare map<string, MyVar> e vector<Record>, senza puntatori
2) (IMHO la migliore) farti delle belle classi Table e Record.


 inutile scervellarsi a reinventare la ruota.
Potresti darmi qualche informazione o qualche riferimento?
Grazie

 ciao Anto
 
Si,ma ripeto dovrei incapsulare il tutto in una classe che in realtà non
aggiungerebbe nessuna funzionalità alle strutture della libreria
standard. Sarebbe un livello in più, costituito da un semplice "guscio
stupido", in quanto le operazioni che mi fornisce la libreria sono più
che sufficienti...
Grazie della risposta

 Potresti darmi qualche informazione o qualche riferimento?
Se fai una ricerca su qualunque motore trovi sicuramente quante
informazioni vuoi su ADO.


 
Ho provato, ma trovo un sacco di
informazioni sugli Active Data Objects di M$, non credo che sia
quello che dicevi tu. Nel caso lo sia, sinceramente non mi interessa più
di tanto, a me interessa la portabilità del codice.

di tanto, a me interessa la portabilità del codice.
Su quali e quante piattaforme prevedi di portare il tuo programma ?


Un livello di astrazione in piů, 
Se vuoi, puoi seguire uno schema simile a quello creato da Borland con
i ClientDataSet.


 di tanto, a me interessa la portabilità del codice.
Infatti non ti consigliavo di utilizzare componenti già fatti ma di
sviluppare la tua interfaccia seguendo il modello ADO. Dato che questo
si occupa di campi, tabelle, query, etc. ed è uno dei più testati,
pensavo che fosse proprio il tipo di modello che faceva per te.


 Su quali e quante piattaforme prevedi di portare il tuo programma ?
 
Windows, Linux, Free/open bsd, Mac (probabilmente solo OSX) come minimo

 
Ah, ok. Ma il mio problema non è tanto un modello, una specie di modello
di gerarchia ce l'ho già in mente. Il mio problema è più
l'implementazione di un tale modello. 
Grazie lo stesso