[Risolto] Salvare data da JFormattedTextField in MySql

di il
11 risposte

[Risolto] Salvare data da JFormattedTextField in MySql

Ciao a tutti,
mi sto arrovellando da settimane su questa situazione.
Ho un campo di tipo JFormattedTextField in cui viene inserita una data di nascita.
Voglio salvarlo in un campo di una tabella MySql definito come Date (ovvero voglio salvare solo il giorno, mese e anno).

Uso Java 1.7.0_25 su Windows XP
Xampp 1.8.2
phpMyAdmin 4.2.7.1
MySql Server 5.5

Ho un metodo generico per salvare un record in una tabella, al quale passo 3 argomenti:
Il nome della tabella.
Un vettore di stringhe con i nomi dei campi della tabella.
Un vettore di oggetti in cui ho caricato i valori da assegnare ai vari campi.

Un elemento del vettore contiene la data ricavata dal suddetto campo.

Il problema è che non riesco a trasferire l'oggetto in una data nel formato adatto a MySql.

In pratica, semplificando, ho:

Definizione
public java.util.Date dataDiNascita;
Carico dal JFormattedTextField alla variabile
dataDiNascita =  (java.util.Date) MskBirthDay.getValue();
Copio la data in un elemento del vettore di oggetti
Object valoriRecord[] = new Object[dimensioneVettore];
  valoriRecord[indice] = dataDiNascita;
Prima della scrittura nel db preparo la query con un
PreparedStatement ps = dbConn.prepareStatement(query);
Quando trovo un elemento di tipo data:
  if (valoriRecord[indice] instanceof java.util.Date) {
cerco di convertirlo nel formato java.sql.Date
E qui inizia il calvario, perché ho provato tutte le soluzioni che ho trovato sul web, ma non sono riuscito a farne funzionare una.

L'ultima che ho provato è:
  SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
  java.util.Date dTmp = new         java.util.Date(sdf.parse(valoriRecord[indice].toString()).getTime());
  java.sql.Date sqlDate = new java.sql.Date(dTmp.getTime());
  ps.setDate(indice, sqlDate);
Ma sulla ps.setDate (per esempio con data = "10/05/1988") mi da l'errore:
Unparseable date: "Sun May 10 00:00:00 CEST 1988"

Ho provato anche col formato "dd-MM-yyyy" ma nulla.

Qualche dritta?

11 Risposte

  • Re: [Risolto] Salvare data da JFormattedTextField in MySql

    Aggiornamento:
    Ho provato a non inserire il campo dataDiNascita nel vettore di oggeti, ma l'ho aggiunto, come argomento a parte, del metoto che salva il record,
    ovvero oltre al campo "Date data" passo un "int idData" che indica l'indice del campo data:
    java.sql.Date sqlDate = new java.sql.Date(data.getTime());
    ps.setDate(idData, sqlDate);
    In questo modo funziona, ma complica troppo il codice, per via dell'aggiunta degli argomenti dei vari metodi coinvolti.
    Anche perché se le date dovessero essere più di una, dovrei gestirmi un'altro vettore solo per le date.

    In pratica sembra che il problema sia il passaggio attraverso l'assegnazione della dataDiNascita ad un oggetto, per poi ritrasformarlo in Date.

    Domanda: ma un vettore di oggetti non dovrebbe poter contenere qualsiasi tipo di dati senza alterarne le caratteristiche?
    Qualche suggerimento?
  • Re: [Risolto] Salvare data da JFormattedTextField in MySql

    Non ho capito quale sia la difficoltà.
    Se hai un oggetto di tipo java.util.Date, per poterlo usare all'interno di una PreparedStatement devi costruire un java.sql.Date a partire dall'oggetto originale e il modo per farlo l'hai già postato qui sopra. Quindi, preso dal vettore l'oggetto e verificato che si tratta di un java.util.Date, crei l'oggetto java.sql.Date corrispondente e applichi il setDate() al posto opportuno.

    ZioCrick ha scritto:


    Domanda: ma un vettore di oggetti non dovrebbe poter contenere qualsiasi tipo di dati senza alterarne le caratteristiche?
    Qualche suggerimento?
    Se il vettore è di tipo Object[] ovviamente sì, ma questo vale in generale: un oggetto non può mutare le sue caratteristiche... come nasce, muore, non esiste la "trasformazione", semmai la creazione di un nuovo oggetto.


    Ciao.
  • Re: [Risolto] Salvare data da JFormattedTextField in MySql

    Grazie mille LeleFT per la tua risposta.

    Per chiarire meglio, ho creato un singolo metodo che raggruppa sinteticamente le operazioni che vengono eseguite, dal prelievo dei dati dai campi della form fino al salvataggio nel database, ma che nel programma reale sono distribuite su varie classi.

    Il problema nasce dalla necessità di passare i dati tramite un vettore di oggetti, che all'apparenza in questo esempio potrebbe essere superfluo.
    Infatti nell'esempio ho usato solo un campo testo e una data, ma nel caso reale ci sono più tabelle e vari tipi di dati, variabili anche in quantità, perché ho realizzato delle classi con metodi generici per gestire qualsiasi tipo di tabelle.

    Riporto il contenuto del metodo così lo puoi provare:
    NB: la dbConn è la connessione al database.
    
    //--------------------------------------------------------------------------------
    //  Prelevo i valori dai campi del JFrame.
        String nome = TxtTesto.getText();
        java.util.Date data = (java.util.Date) MskBirthDay.getValue();
    //--------------------------------------------------------------------------------
    //  Popolo il vettore di oggetti.
        Object valori[] = new Object[2];
        valori[0] = nome;
        valori[1] = data;
        for (int jj=0; jj<valori.length; jj++) {
          System.out.println("(" + jj + ") Valore = " + valori[jj]);
        }
    //--------------------------------------------------------------------------------
    //  Preparo e formatto la stringa della query.
        try {
          String query = "INSERT INTO Persone (Nome, DataDiNascita) VALUES (?, ?);" ;
          PreparedStatement ps = dbConn.prepareStatement(query);
          for (int jj=0; jj<valori.length; jj++) {
            System.out.println("jj = " + jj);
            if (valori[jj] instanceof java.util.Date) {
              if (valori[jj] == null) {
                ps.setNull(jj+1, java.sql.Types.DATE);
              } else {
                try {
                  SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
                  java.util.Date dTmp = new java.util.Date(sdf.parse(valori[jj].toString()).getTime());
                  java.sql.Date sqlDate = new java.sql.Date(dTmp.getTime());
                  System.out.println("riconosciuta");
                  ps.setDate(jj+1, sqlDate);
                } catch (Exception e) {
                  System.out.println("*** Errore: " + e.getMessage());
                  ps.setNull(jj+1, java.sql.Types.DATE);
                }
              }
            } else if (valori[jj] instanceof java.lang.String) {
              if (valori[jj] == null) {
                ps.setNull(jj+1, java.sql.Types.VARCHAR);
              } else {
                ps.setString(jj+1, valori[jj].toString());
              }
            }
          }
          int esito = ps.executeUpdate();
          System.out.println("esito = " + esito);
        }
        catch (SQLException ex) {
          JOptionPane.showMessageDialog(null, ex.getMessage());
          Logger.getLogger(DbMgr.class.getName()).log(Level.SEVERE, null, ex);
        }
    
    Ho aggiunto un po di println per tracciare l'esecuzione, e se lo esegui, il risultato è la stampa del messaggio di errore.

    Se riesci ad aiutarmi a risolvere l'inghippo hai una birra assicurata.
  • Re: [Risolto] Salvare data da JFormattedTextField in MySql

    Ciao.
    Stai facendo un po' di cose inutili e altre concettualmente sbagliate.
    1) Non ha senso passare per i formattatori (SimpleDateFormat e compagnia bella) per fare ciò che serve a te.
    2) Se il test con instanceof ha dato esito positivo, allora l'oggetto è per forza di cose diverso da null, quindi l'if successivo che ne controlla la nullità non serve ed è concettualmente sbagliato.
    3) Ti consiglio di usare sempre il printStackTrace() dell'eccezione quando ne viene sollevata una: la stampa del solo messaggio spessissimo è troppo poco per capire dove stia veramente il problema.

    Andiamo con ordine: prima vediamo cosa puoi fare con ciò che hai predisposto, poi ti fornisco una soluzione per il problema dei NULL (ci sono già passato).

    Se valori[jj] è di tipo java.util.Date, va semplicemente creato un oggetto java.sql.Date corrispondente e usato nella PreparedStatement:
    
    if (valori[jj] instanceof java.util.Date) {
       try {
          java.util.Date myDate = (java.util.Date) valori[jj];
          java.sql.Date d = new java.sql.Date( myDate.getTime() );
          ps.setDate(jj+1, d);
       } catch (Exception e) {
          e.printStackTrace();   // Stampo lo stackTrace!
       }
    }
    
    Questo è tutto ciò che puoi fare con la struttura che hai predisposto (ovvero un array di Object). In pratica, non puoi avere dei NULL perchè non potresti assegnarli alla PreparedStatement (di più, se tu avessi un valore null nell'array di Object, nessun test con instanceof sarebbe mai verificato).

    Quindi, se tu volessi (e mi pare tu debba) trattare anche il caso di inserimento di un NULL per un campo di una tabella, devi fare uno step in più: ovvero, capire quale tipo di dato va inserito in quel determinato campo.

    Per fare questo hai sostanzialmente 2 strade:
    1) Effettuare una query di selezione sul DB, ottenere quindi un ResultSet, da questo ottenere il ResultSetMetaData e, con questo, indagare il tipo di dato di ciascun campo (molto laborioso)
    2) Utilizzare una struttura dati diversa dall'array di Object, che ti dia anche l'informazione sul tipo di dato (soluzione preferenziale che ho adottato anch'io molte volte)

    Un esempio. Costruisci una semplice classe bean che contenga due informazioni: il tipo di dato e il valore del dato.
    
    public class Campo {
       private int tipo;
       private Object valore;
    
       public Campo(int tipo, Object valore) {
          this.tipo = tipo;
          this.valore = valore;
       }
    
       ...   // getter e setter
    }
    
    A questo punto, invece di usare un array di Object, utilizzerai un array di oggetti Campo:
    
    Campo[] valori = new Campo[2];
    valori[0] = new Campo(java.sql.Types.VARCHAR, nome);
    valori[1] = new Campo(java.sql.Types.DATE, data);
    
    Così facendo hai l'informazione per trattare l'eventuale null:
    
    switch( valori[jj].getTipo() ) {
       case java.sql.Types.DATE:
          if (valori[jj].getValore() != null) {
             ... // Costruisci il java.sql.Date d
             ps.setDate(jj+1, d);
          } else {
             ps.setNull(jj+1, java.sql.Types.Date);
          }
          break;
    
       case java.sql.Types.VARCHAR:
          if (valori[jj].getValore() != null) {
             ps.setString(jj+1, (String) valori[jj].getValore());
          } else {
             ps.setNull(jj+1, java.sql.Types.VARCHAR);
          }
          break;
       ...
    }
    
    Vedi tu se la cosa ti può andare bene.

    Ciao.
  • Re: [Risolto] Salvare data da JFormattedTextField in MySql

    Addirittura la struttura può essere semplificata:
    
    if (valori[jj].getValore() != null) {
       switch( valori[jj].getTipo() ) {
          case java.sql.Types.DATE:
             java.sql.Date d = new java.sql.Date( ((java.util.Date) valori[jj].getValore()).getTime() );
             ps.setDate(jj+1, d);
             break;
    
          case java.sql.Types.VARCHAR:
             ps.setString(jj+1, (String) valori[jj].getValore());
             break;
    
          ...
       }
    } else {
       // Il valore è nullo, non mi interessa nemmeno discriminare il tipo con lo switch, tanto ho già il tipo che mi serve
       ps.setNull(jj+1, valori[jj].getTipo());
    }
    
  • Re: [Risolto] Salvare data da JFormattedTextField in MySql

    Caro LeleFT non so come ringraziarti per la tua estesa e chiara spiegazione.
    Nel contempo mi sento più che mai basito, perché mi sembra che la tua soluzione fosse la prima che provai qualche settimana fa.
    Purtroppo nel vortice delle prove che ho fatto, ne ho perso traccia ...
    Ed è probabile che non abbia funzionato per qualche altra mia castroneria che non riuscii ad individuare come la causa del malfunzionamento.

    A questo punto mi viene una riflessione: invece di usare la struttura, sicuramente molto elegante, dell'array di oggetti Campo, non risulta più semplice impostare la tabella del db con i valori di default per ogni campo della tabella?
    Che tra l'altro è quello che ho fatto io per realizzare il programmino che inseriva solo un campo testo e la data, in una tabella con molti più campi.
    Secondo te ci possono essere delle controindicazioni?

    Perdona la mia probabile ingenuità ma fai conto che provengo da decenni di programmazione professionale in Assembler, Fortran IV e 77, C, con cui smanettavo con i byte e i bit e infine Visual Basic (dal 3 al 6) con db Access ed SQL Server ... ma ormai non lo faccio più da anni ... per cui ora che sto cercando di riprendere a programmare (per uso personale), l'ambiente OOP mi risulta ancora una fumosa diavoleria e Java di una complessità mefistofelica!
  • Re: [Risolto] Salvare data da JFormattedTextField in MySql

    La soluzione che ti ho proposto è figlia di quello che ho visto che provavi a fare, quindi non è LA soluzione, ma solo UNA soluzione. Dipende sempre da ciò che intendi fare.
    Puoi impostare la tabella affinchè ciascun campo abbia un valore di default (se questo è accettabile a livello di progettazione del DB stesso).
    Altra soluzione può essere quella di decidere di creare l'array con tutti e soli i campi "necessari", assumendo come vera l'ipotesi che tutti i valori dell'array siano non nulli. A questo punto la query può essere costruita per effettuare l'insert solo sui campi interessati, lasciando che sia il DB a popolare con NULL gli altri campi (un po' come hai fatto tu nell'ultimo esempio) e quindi non prendere nemmeno in considerazione l'idea di usare il setNull().
    Tutto dipende dalle tue esigenze e dalle tue scelte di progettazione.

    Ad ogni modo l'impatto con la programmazione ad oggetti può essere effettivamente "doloroso" se non è accompagnato da dei libri di testo o dallo studio in aula. Nella mia storia sono transitato per BASIC, Pascal, Delphi, VB (dal 4 al 6) e C, prima di incontrare Java all'università molti anni fa (ora Java è il mio lavoro). Ma, appunto, stavo seguendo un corso universitario, con spiegazioni in aula. Se posso darti un consiglio, acquista un buon libro su Java (io ho recentemente acquistato quello di Claudio De Sio Cesari e lo trovo ben scritto, anche se qua e là non manca di errori ed imprecisioni), ti aiuterà a scavalcare l'ostacolo principale (dopotutto, non è l'esperienza di programmazione quella che ti manca, solo l'approccio Object Oriented ai problemi).

    Ciao.
  • Re: [Risolto] Salvare data da JFormattedTextField in MySql

    Chiarissimo!
    In effetti prima di iniziare con Java mi sono letto, quasi tutto, il documento pdf "Object Oriented && Java 5 (II Edizione)" proprio di Claudio De Sio Cesari, oltre ad altri testi on-line e visionato video etc. ... ma evidentemente non basta ancora per quei due neuroni che mi sono rimasti nella teca cranica.
    Grazie ancora.
  • Re: [Risolto] Salvare data da JFormattedTextField in MySql

    Acc! Un momento!
    Sto incontrando un altro inconveniente.
    Continuo qua perché riguarda lo stesso argomento.

    Stavo provando ad implementare la struttura con lo switch, ma non mi riconosce i getTipo e getValore.

    Può dipendere dal fatto che sono metodi introdotti in versioni recenti di Java?
    Perché io, per questioni di compatibilità con Windows XP sto utilizzando Java Versione 1.7.0_25
  • Re: [Risolto] Salvare data da JFormattedTextField in MySql

    No, sono metodi che devi implementare tu nella classe Campo: li avevo semplicemente indicati col commento // getter e setter (pensavo fosse chiaro):
    
    public class Campo {
       private int tipo;
       private Object valore;
    
       public Campo(int tipo, Object valore) {
          this.tipo = tipo;
          this.valore = valore;
       }
    
       // I getter ...
       public int getTipo() {
          return tipo:
       }
       
       public Object getValore() {
          return valore;
       }
    }
    
    In realtà i setter non ti servono, hai già il costruttore che è più che sufficiente.
  • Re: [Risolto] Salvare data da JFormattedTextField in MySql

    LeleFT ha scritto:


    No, sono metodi che devi implementare tu nella classe Campo: li avevo semplicemente indicati col commento // getter e setter (pensavo fosse chiaro):
    AH! Scusa, mi sono confuso perché nell'esempio che mi hai mostrato li hai usati sul mio vettore di oggetti valori[jj]:
    switch( valori[jj].getTipo() ) {
          case java.sql.Types.DATE:
             java.sql.Date d = new java.sql.Date( ((java.util.Date) valori[jj].getValore()).getTime() );
             ps.setDate(jj+1, d);
             break;
    Ok, adesso credo di aver capito.
Devi accedere o registrarti per scrivere nel forum
11 risposte