# foreignkey abfragen und speichern



## didi577 (26. Jan 2017)

Hallo,

ich  möchte aus einer Tabelle die Bezeichnungsspalte anzeigen aber dessen key in einer anderen Tabelle speichern. Ich lade die Tabelle in eine Combobox:

```
public void ladenBoxDozent(DefaultComboBoxModel boxDozent, String sql) {

       PreparedStatement pst = null;
       ResultSet rs = null;

       try {
           pst = con.prepareStatement(sql);
           rs = pst.executeQuery();
           while (rs.next()) {
               boxDozent.addElement(rs.getString(1));
           }

       } catch (SQLException e) {
           StringWriter s = new StringWriter();
           e.printStackTrace(new PrintWriter(s));
           System.out.println(s.toString());

       } finally {
           if (rs != null && pst != null) {
               try {
                   rs.close();
                   pst.close();
               } catch (SQLException e) {
                   e.printStackTrace();
               }
           }
       }
   }
```
das funktioniert gut. Die Auswahl dieser Combobox speicher ich mit anderen Daten in einer anderen Tabelle ab. Ich will aber nicht das Bezeichnungsfeld aus der Combobox speichern sondern die ID dieses Datensatzes. Ich habe die andere Tabelle schon soweit vorbereitet dass ich für die Spalten foreignkeys hinterlegt habe. Wie muss ich die Abfrage oder umbauen um den foreignkey statt der Spalte Bezeichnung abzuspeichern?


----------



## Joose (26. Jan 2017)

Anstatt nur den Bezeichner der ComboBox hinzuzufügen, würde Dozent Objekte hinzufügen. Diese Objekte enthalten alle benötigten Daten, wenn ein Item dann selektiert wurde kannst du von dem selektierten Dozent Objekt mittels setter ganz einfach die ID abfragen.


----------



## didi577 (26. Jan 2017)

Danke, für deinen Hinweis. (Sorry, ich habe aber den falschen Code gesendet) Bislang habe ich immer in den Spalten alle Bezeichnungen gespeichert aber ich glaube vor dem Hintergrund normalisierter DB ist es auf Dauer performanter die IDs zu speichern.
Nun, zur Umsetzung. In der GUI rufe ich "boxenLaden()" beim Fensterstart auf:

```
mysql.boxenLaden(boxDozentM, "select name from dozenten ORDER BY name");
```
das ist boxenLaden():

```
public void boxenLaden(DefaultComboBoxModel boxModel, String sql) {

       PreparedStatement pst = null;
       ResultSet rs = null;

       try {

           pst = con.prepareStatement(sql);
           rs = pst.executeQuery();
           while (rs.next()) {
               boxModel.addElement(rs.getString(1));
           }
       } catch (SQLException e) {
           StringWriter s = new StringWriter();
           e.printStackTrace(new PrintWriter(s));
           System.out.println(s.toString());

       } finally {
           if (rs != null && pst != null) {
               try {
                   rs.close();
                   pst.close();
               } catch (SQLException e) {
                   e.printStackTrace();
               }
           }
       }
   }
```

das sind die zugehörigen Widgets in der GUI:

```
boxDozentM = new DefaultComboBoxModel();
       boxDozent = new JComboBox(boxDozentM);
```

wo muss ich hier ansetzen um deinen Vorschlag umzusetzen?


----------



## Joose (26. Jan 2017)

Du musst dein SELECT Statement anpassen und in "boxenLaden" in der while-Schleife deine Dozent Objekte erstellen.


----------



## didi577 (26. Jan 2017)

puh ich kämpfe...
ich glaube das verschiebe ich noch etwas bis ich fitter in dem Thema bin

kann man sowas nachträglich umstellen?


----------



## Joose (26. Jan 2017)

Was umstellen? Man kann nachträglich vieles anpassen/umstellen, die Frage ist lohnt sicher der Aufwand gegenüber dem Gewinn?


----------



## didi577 (26. Jan 2017)

mit umstellen meine ich auf die Arbeit mit foreign keys und einer normalisierten DB. mir fehlt die Erfahrung ob es sich lohnt diesen Aufwand zu betreiben oder damit zu leben dass Namen und Orte ggf. hundertfach in der DB auftauchen statt deren keys


----------



## JAVAKEK (27. Jan 2017)

didi577 hat gesagt.:


> damit zu leben dass Namen und Orte ggf. hundertfach in der DB auftauchen statt deren keys



Da hast du doch schon deine Antwort  "Beiss" dich durch das Thema durch und mache es von Anfang an ordentlich. Im moment fügst du lediglich die Namen zu der ComboBox hinzu. Wie du schon bemerkt hast fehlt dir an der Stelle der key. Passe deine SQL so an, dass du nicht nur den namen bekommst sondern auch den key des Dozenten. Wenn du dann das Ergebnis des Selects durchläufst, erstellst du dir ein Dozent Objekt, welches die relevanten Attribute enthält die du benötigst.
Dann kannst du das gesamte Dozenten Objekte als Element zur Box hinzufügen.
Hier ist nochmal ein Teil veranschaulicht:
http://stackoverflow.com/questions/17887927/adding-items-to-a-jcombobox


----------



## Joose (27. Jan 2017)

didi577 hat gesagt.:


> mit umstellen meine ich auf die Arbeit mit foreign keys und einer normalisierten DB. mir fehlt die Erfahrung ob es sich lohnt diesen Aufwand zu betreiben oder damit zu leben dass Namen und Orte ggf. hundertfach in der DB auftauchen statt deren keys



Der Aufwand lohnt sich auf jedenfall, ein nachträgliches normalisieren is zwar machbar aber auch mit viel Arbeit verbunden.
Dein jetztiges Problem wird sein wenn du mal den Namen ändern willst, musst du alle Tabellen durchgehen, schauen wo der Name vorkommt und ihn ändern (sofern der Key auch dazu passt)


----------



## didi577 (27. Jan 2017)

Moin,

Danke für eure Hinweise. Werde mich übers Wochenede einschließen und basteln.

Habe noch eine Baustelle in diesem Projekt. Ich erstelle Auswertungen die in einer GUI angezeigt werden und die ich dann per Mail versenden möchte. Für den Mailversand wurde mir hier ein Code empfohlen den ich übernommen und etwas angepasst habe:

```
package auswertung;


import java.util.Date;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

/**
 * @author zeja
 */
public class Mail {


   public void sendMail(String smtpHost, String username, String password, String senderAddress,
           String recipientsAddress, String subject, String text) {
       MailAuthenticator auth = new MailAuthenticator(username, password);

       Properties properties = new Properties();

       // Den Properties wird die ServerAdresse hinzugefügt
       properties.put("mail.smtp.host", smtpHost);
   

       // !!Wichtig!! Falls der SMTP-Server eine Authentifizierung
       // verlangt
       // muss an dieser Stelle die Property auf "true" gesetzt
       // werden
       properties.put("mail.smtp.auth", "true");
       properties.put("mail.smtp.starttls.enable", "true");

       // Hier wird mit den Properties und dem implements Contructor
       // erzeugten
       // MailAuthenticator eine Session erzeugt
       Session session = Session.getDefaultInstance(properties, auth);

       try {
           // Eine neue Message erzeugen
           Message msg = new MimeMessage(session);

           // Hier werden die Absender- und Empfängeradressen gesetzt
           msg.setFrom(new InternetAddress(senderAddress));
           msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(recipientsAddress, false));

           // Der Betreff und Body der Message werden gesetzt
           msg.setSubject(subject);
           msg.setText(text);

           // Hier lassen sich HEADER-Informationen hinzufügen
           msg.setHeader("Test", "Test");
           msg.setSentDate(new Date());

           // Zum Schluss wird die Mail natürlich noch verschickt
           Transport.send(msg);

       } catch (Exception e) {
           e.printStackTrace();
       }
   }

   class MailAuthenticator extends Authenticator {
       
       /**
        * Ein String, der den Usernamen nach der Erzeugung eines Objektes<br>
        * dieser Klasse enthalten wird.
        */
       private final String user;

       /**
        * Ein String, der das Passwort nach der Erzeugung eines Objektes<br>
        * dieser Klasse enthalten wird.
        */
       private final String password;

       /**
        * Der Konstruktor erzeugt ein MailAuthenticator Objekt<br>
        * aus den beiden Parametern user und passwort.
        *
        * @param user
        *            String, der Username fuer den Mailaccount.
        * @param password
        *            String, das Passwort fuer den Mailaccount.
        */
       public MailAuthenticator(String user, String password) {
           this.user = user;
           this.password = password;
       }

       /**
        * Diese Methode gibt ein neues PasswortAuthentication Objekt zurueck.
        *
        * @see javax.mail.Authenticator#getPasswordAuthentication()
        */
       protected PasswordAuthentication getPasswordAuthentication() {
           return new PasswordAuthentication(this.user, this.password);
       }
   }

   public static void main(String[] args) {

       String username = "xxx";
       String password = "xxx";
       String senderAddress = "xxx";// someone@web.de
       String recipientsAddress = "xxx"; // somereceiver@web.de
       String subject = "Schulungsauswertung";
       String text = "Hallo ..., du hast am eine Schulung durchgeführt.";
       String smtpHost = "smtp.gmail.com";

       new Mail().sendMail(smtpHost, username, password, senderAddress, recipientsAddress, subject, text);
   }
}
```

das funktioniert so als Klasse. Es werden Mails versendet. Ich möchte den Versend aber mit Klick auf einen Button erreichen. D.h. die main Methode muss raus und ich muss den Versand in den ActionListener des Button (bereits vorhanden) verlagern. Wie stelle ich das am besten an?


----------



## Joose (27. Jan 2017)

Wo genau liegt das Problem nun? Die main-Methode ist nichts anderes als ein Startpunkt  von welchem du ganz normal Objekte erstellen kannst und deren Methoden aufrufen kannst. Du könntest die main-Methode ganz einfach mit der "actionPerformed" des ActionListener deines Buttons ersetzen.
Was hindert dich daran im ActionListener des Buttons einfach ein Mail-Objekt zu erstellen und von diese die sendMail Methode aufzurufen?


----------



## didi577 (27. Jan 2017)

oh Mann, die Lösung liegt so nah...
hab den Code aus der main jetzt in den ActionListener gepackt und es läuft


Joose hat gesagt.:


> Was hindert dich daran im ActionListener des Buttons einfach ein Mail-Objekt zu erstellen und von diese die sendMail Methode aufzurufen?


...ist sicher der elegantere Weg, auch das werde ich hinbekommen


----------



## didi577 (27. Jan 2017)

ich bin jetzt wieder bei meinem anfangs beschriebenen Datenbankproblem. Ich habe jetzt wie von @AG10 empfohen eine Klasse aufgemacht (für eine andere Tabelle erstmal, sie hat drei Spalten):

```
public class KursElemente {
   
   private String kurs_id;
   private String kursnr;
   private String bezeichnung;
   
   public KursElemente(String kurs_id, String kursnr, String bezeicnung) {
       
       this.kurs_id = kurs_id;
       this.kursnr = kursnr;
       this.bezeichnung = bezeicnung;
       
   }
   
   public String toString() {
       
       return kurs_id;
   }
   
   public String getKurs_Id() {
       
       return kurs_id;
   }
   
   public String getKursnr() {
       
       return kursnr;
   }
   
   public String getBeeichnung() {
       
       return bezeichnung;
   }

}
```
dazu habe ich die SQL angepasst (ich möchte alle drei Spalten im Objekt speichern):

```
public void boxKursLaden(DefaultComboBoxModel boxKursM, String sql) {

       PreparedStatement pst = null;
       ResultSet rs = null;

       try {

           pst = con.prepareStatement(sql);
           rs = pst.executeQuery();
           while (rs.next()) {
               boxKursM.addElement(new KursElemente(rs.getString(0), rs.getString(1), rs.getString(2)));
               System.out.println(rs.getString(1));
           }
       } catch (SQLException e) {
           StringWriter s = new StringWriter();
           e.printStackTrace(new PrintWriter(s));
           System.out.println(s.toString());

       } finally {
           if (rs != null && pst != null) {
               try {
                   rs.close();
                   pst.close();
               } catch (SQLException e) {
                   e.printStackTrace();
               }
           }
       }
   }
```
hier ist der Aufruf wenn ich in der GUI die Box laden möchte:

```
mysql.boxKursLaden(boxKursM, "select kursnr from kurse ORDER BY kursnr");
```

das klappt nur noch nicht. ich möchte die Spalte kursnr in der Combobox angezeigt bekommen, beim Programmstart kommt ein SQL Fehler:
_java.sql.SQLException: Column Index out of range, 0 < 1.
   at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:964)....
_
diese Zeile scheint das Problem zu sein:

```
boxKursM.addElement(new KursElemente(rs.getString(0), rs.getString(1), rs.getString(2)));
```

wo ist mein Fehler? ich komme leider nicht weiter


----------



## Meniskusschaden (27. Jan 2017)

Du versuchst auf drei Spalten zuzugreifen, obwohl du dir nur eine geholt hast.

EDIT: Ausserdem beginnt die Zählung bei 1 und nicht bei 0.


----------



## didi577 (28. Jan 2017)

ok, Danke

habe die Abfrage angepasst:

```
public void boxKursLaden(DefaultComboBoxModel boxKursM, String sql) {

       PreparedStatement pst = null;
       ResultSet rs = null;

       try {

           pst = con.prepareStatement(sql);
           rs = pst.executeQuery();
           while (rs.next()) {
               boxKursM.addElement(new KursElemente(rs.getString(1), rs.getString(2), rs.getString(3)));
               System.out.println(rs.getString(1));
           }
       } catch (SQLException e) {
           StringWriter s = new StringWriter();
           e.printStackTrace(new PrintWriter(s));
           System.out.println(s.toString());

       } /*finally {
           if (rs != null && pst != null) {
               try {
                   rs.close();
                   pst.close();
               } catch (SQLException e) {
                   e.printStackTrace();
               }
           }
       }*/
   }
```

was muss ich in der select anpassen? 

```
mysql.boxKursLaden(boxKursM, "select kurse from kurse ORDER BY kursnr");
```

ich möchte vom Kurselement in der Combobox nur die Spalte kursnr angezeigt bekommen

egal wierum ich es erfasse ich bekoome immer sql Exceptions


----------



## JAVAKEK (28. Jan 2017)

Mit try&error kommt man irgenwann nicht mehr weiter. Du musst auch ein wenig verstehen was du da tippst. Probiere mal die Fragen zu beantworten, dann kommst du selber auf die Antwort was falsch ist:

Was passiert hier?
rs.getString(1), rs.getString(2), rs.getString(3)

Was bekommst du bei dem Query als Result?
select kurse from kurse ORDER BY kursnr


----------



## didi577 (29. Jan 2017)

hi, ich komme leider erst jetzt wieder dazu

klar ich verstehe noch nicht alles, arbeite mich aber immer weiter ein

so ich habe jetzt ein Ergebnis ;-), habe in der select jetzt die anderen Spalten aufgenommen:

"select kurse_id, kursnr, bezeichnung from kurse ORDER BY kursnr"

das hatte ich vorher auch schon probiert nur leider immer einen Tippfehler in einer Spaltenbezeichnung und daher Fehler 

wie kann ich steuern dass die Spalte kursnr in der Combobox angezeigt wird? ich habe diese Spalte in der select mal an die erste Stelle gesetzt, dann wird die kursnr auch angezeigt aber ist das auch der richtige Weg?


----------



## Meniskusschaden (29. Jan 2017)

Kann es sein, dass du deinen eigenen Code nicht verstanden hast?
In der Combo-Box erscheint das, was die toString-Methode des dort gespeicherten Objektes zurück liefert. Die Reihenfolge der Spalten des ResultSets entspricht der Reihenfolge der Spalten des Select-Statements.


----------



## Joose (30. Jan 2017)

Anmerkung zu deiner Klasse "KursElemente":

Eine Klasse beschreibt *einen *Gegenstand genauer bzw. ist der Bauplan für *ein *Objekt. Betonung liegt hier auf *"einen"* bzw.* "ein"*.
Sprich du solltest die Klasse in "KursElement" umbenennen. Da ein Objekt davon auch nur ein Element beschreibt.
Und vermeide "_" in Klassen, Attributen und Methodenamen.

In der Methode "boxKursLaden" steht folgender Code:

```
} catch (SQLException e) {
           StringWriter s = new StringWriter();
           e.printStackTrace(new PrintWriter(s));
           System.out.println(s.toString());
```
Gibt es einen Grund warum du einen StringWriter erstellst usw.? Warum schreibst du nicht einfach `e.printStackTrace();` und fertig?


----------



## didi577 (30. Jan 2017)

Hallo,

habe die DB angepasst und speichere jetzt den key. Meine speichern routine muss sicher angepasst werden da ich ja bislang den Inhalt der Combobox ausgelesen habe:

```
mysql
               .speichern(boxKurs.getSelectedItem()...
```
jetzt habe ich ja die Objekte in der Combobox

```
boxKursM.addElement(new KursElemente(rs.getString(1), rs.getString(2), rs.getString(3)));
           }
```
die in der Box angezeigt werden. String 1 wird in der Box angezeigt und String 2 will ich speichern. Wenn ich den Code so belasse speichert er immer 1 egal welchen Comboboxeintrag ich ausgewählt habe. Ich vermute dass ich "(boxKurs.getSelectedItem()" und "KursElemente" mit "getKurs_id" zusammenbringen muss.
Kann mir jemand helfen?


----------



## didi577 (30. Jan 2017)

Joose hat gesagt.:


> Anmerkung zu deiner Klasse "KursElemente":


 danke für die Hinweise, werde es korrigieren


----------



## Joose (30. Jan 2017)

didi577 hat gesagt.:


> die in der Box angezeigt werden. String 1 wird in der Box angezeigt und String 2 will ich speichern. Wenn ich den Code so belasse speichert er immer 1 egal welchen Comboboxeintrag ich ausgewählt habe. Ich vermute dass ich "(boxKurs.getSelectedItem()" und "KursElemente" mit "getKurs_id" zusammenbringen muss.
> Kann mir jemand helfen?



DefaultComboBoxModel ist generisch, wenn du als generischen Typ deine Klasse KursElement angibst dann bekommst du "getSelectedItem()" ein KursElement zurück von welchem du dann die entsprechende getter Methode aufrufen kannst.
https://docs.oracle.com/javase/7/docs/api/javax/swing/DefaultComboBoxModel.html


----------



## didi577 (30. Jan 2017)

hm...??
ich muss die KursElement Klasse so definieren?:

```
public class KursElement <K>
```

in das DefaultComboboxModel so kennzeichnen?:

```
boxKursM = new DefaultComboBoxModel<K>();
```

nee das funktioniert nicht 

mit der API tue ich mich sehr schwer, grundsätzlich glaube ich was gemeint ist, ich habe nur noch keinen Ansatz wie ich dem Model sage dass die Klasse KursElement die Daten liefert ?!


----------



## Joose (30. Jan 2017)

didi577 hat gesagt.:


> ich muss die KursElement Klasse so definieren?:
> 
> ```
> public class KursElement <K>
> ```


Nein so machst du die Klasse KursElement generisch, du sollst aber der schon generische Klasse "DefaultComboBoxModel" den Typparameter angeben.



didi577 hat gesagt.:


> in das DefaultComboboxModel so kennzeichnen?:
> 
> ```
> boxKursM = new DefaultComboBoxModel<K>();
> ...


`DefaultComboBoxModel<KursElement> boxKursM = new DefaultComboBoxModel<KursElement>();`
Das selbe Prinzip wie bei der ArrayList (die auch generisch ist)


----------



## didi577 (30. Jan 2017)

oh Danke, die LIste meiner Nacharbeiten zum "verstehen" wird immer länger 

jetzt meckert er aber die Zeile danach an:

```
boxKurs.setModel(boxKursM);
```
ich muss doch aber das Model setzen, oder?


----------



## Joose (30. Jan 2017)

didi577 hat gesagt.:


> jetzt meckert er aber die Zeile danach an:
> 
> ```
> boxKurs.setModel(boxKursM);
> ```



Wie sonst auch: Bitte immer die Fehlermeldung dazu posten


----------



## didi577 (30. Jan 2017)

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
   The method setModel(ComboBoxModel<String>) in the type JComboBox<String> is not applicable for the arguments (DefaultComboBoxModel<KursElement>)


----------



## Joose (30. Jan 2017)

Dann schau dir mal an wie deine JComboBox deklariert ist und schau dir die entsprechende Dokumentation bzw. den Code der JComboBox an.
So sollte dir einleuchten was das Problem ist


----------



## didi577 (30. Jan 2017)

erledigt  war die Deklaration

jetzt kommt eine NPE Meldung

an der Stelle:


```
boxKursM.addElement(new KursElement(rs.getString(1), rs
                       .getString(2), rs.getString(3)));
```

ist in der SQL die Zeile nach der while Schleife


----------



## Meniskusschaden (30. Jan 2017)

didi577 hat gesagt.:


> ich muss doch aber das Model setzen, oder?


Ja, sofern du nicht das bereits vorhandene Model nutzen, sondern der Box ein anderes zuweisen möchtest.


----------



## Meniskusschaden (30. Jan 2017)

didi577 hat gesagt.:


> jetzt kommt eine NPE Meldung
> 
> an der Stelle:


Dann sind boxKursM oder rs oder beide null.


----------



## didi577 (30. Jan 2017)

die NPE kommt erst seitdem ich den generischen Typ angegeben habe, die anderen Boxen (ohne generischen Typ) werden geladen
warum ist boxKursM bzw, rs aufeinmal null?


----------



## Harry Kane (30. Jan 2017)

Wahrscheinlich weil du noch was anderes am Code gemacht hast.


----------



## JAVAKEK (30. Jan 2017)

Falls du noch dein while (rs.next()) { drin hast und sollte rs eig. nicht null sein. Poste nochmal dein Code wie er momentan aussieht.


----------



## didi577 (30. Jan 2017)

Die Abfrage:

```
public void boxKursLaden(DefaultComboBoxModel boxKursM, String sql) {

       PreparedStatement pst = null;
       ResultSet rs = null;

       try {

           pst = con.prepareStatement(sql);
           rs = pst.executeQuery();
           while (rs.next()) {
               boxKursM.addElement(new KursElement(rs.getString(1), rs
                       .getString(2), rs.getString(3)));
           }
       } catch (SQLException e) {
           e.printStackTrace();

       } finally {
           if (rs != null && pst != null) {
               try {
                   rs.close();
                   pst.close();
               } catch (SQLException e) {
                   e.printStackTrace();
               }
           }
       }
   }
```
der Aufruf:

```
mysql.boxKursLaden(boxKursM, "select kursnr, kurse_id, bezeichnung from kurse ORDER BY kursnr");
```

die Combobox:

```
boxKurs = new JComboBox();
       DefaultComboBoxModel<KursElement> boxKursM = new DefaultComboBoxModel<KursElement>();
       boxKurs.setModel(boxKursM);
```
die Klasse des KursElement

```
public class KursElement {
   
   private String kurs_id;
   private String kursnr;
   private String bezeichnung;
   
   public KursElement(String kurs_id, String kursnr, String bezeicnung) {
       
       this.kurs_id = kurs_id;
       this.kursnr = kursnr;
       this.bezeichnung = bezeicnung;
       
   }
   
   public String toString() {
       
       return kurs_id;
   }
   
   public String getKurs_Id() {
       
       return kurs_id;
   }
   
   public String getKursnr() {
       
       return kursnr;
   }
   
   public String getBezeichnung() {
       
       return bezeichnung;
   }

}
```

bevor ich diesen Part eingefügt habe ging es:

```
DefaultComboBoxModel<KursElement> boxKursM = new DefaultComboBoxModel<KursElement>();
```


----------



## Joose (30. Jan 2017)

Lass uns bitte nicht rumraten. Der StackTrace der Exception verrät genau wo der Fehler passiert.
Wenn es sich tatsächlich um `boxKursM.addElement(new KursElement(rs.getString(1), rs.getString(2), rs.getString(3)));` handelt, dann ist entweder `rs` oder `boxKursM` null.
`rs` kann es nicht sein, sonst würde er schon eine Zeile vorher die Exception werfen, als kann nur `boxKursM` null sein.

Nimm den Debugger deiner IDE und kontrolliere einfach deinen Code. Dort wo du `boxKursLaden` aufrufst übergibst du auch das Model, ist es an allen Stelle wo diese Methode aufgerufen wird initialisiert?


----------



## Meniskusschaden (30. Jan 2017)

Ich vermute, dass du boxKursM zwei Mal deklariert hast (z.B. eine lokale Variable und eine Objektvariable) und dass du die Objektvariable an boxKursLaden() übergibst, aber nur der lokalen Variablen ein Objekt zugewiesen hast. Das kann man an den geposteten Ausschnitten aber nicht sehen.


----------



## didi577 (30. Jan 2017)

boxKursM ist null, das hat der Debugger verraten
ich deklariere am Anfang:

```
private DefaultComboBoxModel<String> boxKursM
```
später kommt:

```
DefaultComboBoxModel<KursElement> boxKursM = new DefaultComboBoxModel<KursElement>();
```

die Methode boxKursLaden() beginnt mit:

```
public void boxKursLaden(DefaultComboBoxModel boxKursM, String sql) {
```

der Methodenaufruf:

```
mysql.boxKursLaden(boxKursM, "select kursnr, kurse_id, bezeichnung from kurse ORDER BY kursnr");
```

ich glaube hier ist etwas durcheinander..


----------



## Joose (30. Jan 2017)

Wie @Meniskusschaden schon gesagt hat: du deklarierst lokal eine Variable "boxKursM" welche du initialisierst. Die Instanzvariable initialisierst du nicht, diese übergibst du dann aber an die Methode!
Lösung: statt einer lokalen Variable zu deklarieren und initialisieren, initialisiere nur das Instanzattribut

Abgesehen davon ist die Deklaration deiner Instanzvariable und deiner lokalenVariable unterschiedlich! Und die Methode `boxKursLaden` erwartet als Parameter einfach nur ein DefaultComboBoxModel, verwendet stattdessen als Type für den Parameter DefaultComboBoxModel<KursElement>.


----------



## didi577 (30. Jan 2017)

ich denke ich habe es ...
ich deklariere jetzt:

```
private DefaultComboBoxModel<KursElement> boxKursM;
```
hier erzeuge ich das Objekt:

```
boxKursM = new DefaultComboBoxModel<KursElement>();
```

der Fehler ist weg, danke für eure Hinweise, jetzt kann ich mich endlich wieder meinem eigentlichen Problem widmen


----------



## didi577 (30. Jan 2017)

Joose hat gesagt.:


> wenn du als generischen Typ deine Klasse KursElement angibst dann bekommst du "getSelectedItem()" ein KursElement zurück von welchem du dann die entsprechende getter Methode aufrufen kannst.


ich möchte jetzt erreichen dass die kurs_id von KursElement gespeichert wird
das ist der Aufruf der speichern Methode:

```
mysql
               .speichern(boxKurs.getSelectedItem(),...
```
setze ich hier jetzt an?


----------



## Joose (30. Jan 2017)

Verwende den Debugger und kontrolliere was dir die Methode `getSelectedItem` zurückliefert.
Dann überlege dir was du mit diesem Rückgabewert anfangen kannst


----------



## didi577 (30. Jan 2017)

kannst du mir sagen wo ich nachlesen kann wie ich den Debugger für meine Zwecke richtig einsetzen kann?
habe damit bislang noch nix gemacht


----------



## Joose (30. Jan 2017)

Je nachdem welche IDE du verwendest findest du sicher auf der Produktseite einige Infos dazu.


----------



## didi577 (30. Jan 2017)

ich arbeite mit eclipse..

...werde mal suchen...


----------



## Joose (30. Jan 2017)

Das Prinzip bei jedem Debugger ist eigentlich gleich: du legst mittels Breakpoint fest wo du im Code stehen bleiben willst, danach kannst du überprüfen welchen Wert die Variablen haben oder eben kontrollieren was eine Methode zurückgibt wenn sie ausgeführt wird. 
Entweder gehst du dann per Prozedur- oder Einzelschritt deinen Code durch. Beim Prozedurschritt wird die aktuelle Zeile komplett ausgeführt, beim Einzelschritt debuggst du jeden einzelnen Methodenaufruf in der aktuellen Zeile.
......


----------



## didi577 (30. Jan 2017)

hab mich bis dahin durchgekämpft, habe den breakpoint an der Zeile wo getSelectItem steht gesetzt und bin in den debuggModus, da gehts aber nicht weiter, die Schaltflächen zum springen sind inaktiv


----------



## Harry Kane (30. Jan 2017)

Alternativ könntest du dich auch einfach darin erinnern, was du programmiert hast. Da du deine JComboBox bzw. deren ComboBoxModel mit KursElemeneten befüllst, müssen die aus dem ComboBoxModel abgefragten Objekte vom Typ KursElement sein. Du kannst also das Rückgabewert von boxKurs.getSelectedItem() auf KursElement casten und darauf die Methode getKurs_Id aufrufen:

```
mysql.speichern(((KursElement)boxKurs.getSelectedItem()).getKurs_Id, ...);
```


----------



## didi577 (30. Jan 2017)

vielen Dank, der Code läuft durch, aber in der DB wird nachwievor nicht die kurs_id gespeichert sondern 1, ein 

```
System.out.println(((KursElement)boxKurs.getSelectedItem()).getKurs_Id());
```
 liefert die kursnr die auch in der Box angezeigt wird


----------



## Harry Kane (30. Jan 2017)

Dann macht offenbar der von dir nicht gezeigte Code in mysql.speichern() etwas anderes als du glaubst.
Oh Mann ist das mühsam....


----------



## Joose (30. Jan 2017)

Oder es wird nicht die Kursnr sondern die kurs_id in der Combobox angezeigt


----------



## didi577 (30. Jan 2017)

ja ist echt ärgerlich

```
mysql
               .speichern(((KursElement)boxKurs.getSelectedItem()).getKurs_Id(),
```

wenn ich einen Kurs aus dem hinteren Bereich auswähle dann speichert er ein 2 ???


----------



## didi577 (30. Jan 2017)

in der Combobox wird die kursnr angezeigt, wenn ich die Kurasnummern weit auseinanderliegend auswähle und speichere werden irgendwann 2, 3 oder 4 gespeichert aber nicht die Zuordnungen kurs_id zu kursnr aus der Kurstabelle


----------



## Harry Kane (30. Jan 2017)

Ohne den Code der mysql.speichern() und die Struktur deiner db zu kennen, ist das nur ein rumraten.
Also ich bin raus, das wird mir zu...


----------



## didi577 (30. Jan 2017)

bislang hatte ich nur den Aufruf der mysql gepostet... hier ist mal die Methode:

```
public int speichern(Object boxKurs)
{

       PreparedStatement pst = null;

       try {

           pst = con
                   .prepareStatement("INSERT INTO fragen(kurs) VALUES 
 ('"
                           + boxKurs
                           + "')");
return pst.executeUpdate();
```


----------



## didi577 (30. Jan 2017)

die DB


----------



## Joose (30. Jan 2017)

didi577 hat gesagt.:


> bislang hatte ich nur den Aufruf der mysql gepostet... hier ist mal die Methode:
> 
> ```
> public int speichern(Object boxKurs)
> ...



Hier fängt es schon mal an: Warum übergibst du der Methode "speichern" ein Object? Warum nicht den konkreten Typ den du in die Datenbank speichern willst?
Du solltest anfangen nachzuvollziehen was du da programmierst. Welches Objekt wird angezeigt und welches wird ausgewählt und dann an deine Methode speichern übergeben.
Hilfreich ist dabei der Debugger oder eben Log Ausgaben.

Ich glaub in deiner ComboBox werden immer noch die kurse_id angezeigt und nicht die kursnr und die Methode speichern funktioniert ohne Probleme.


----------



## didi577 (30. Jan 2017)

ok, ich habe speichern gewählt da ich verschiedene Widgets auswerte und speichere

```
public int speichern(Object boxKurs, Object boxDozent, Object boxOrt,
           Object spinDatum, Object auswahlland, Object auswahla1,
           Object auswahla2, Object auswahla3, Object auswahla4,
           Object auswahlb1, Object auswahlb2, Object auswahlb3,
           Object auswahlc1, Object tfC14, Object auswahlc2, Object auswahlc3,
           Object auswahlc4, Object auswahlc5, Object auswahld1,
           Object auswahld2, Object auswahld3, Object tfD4, Object tfD5) {

       PreparedStatement pst = null;

       try {

           pst = con
                   .prepareStatement("INSERT INTO fragen(kurs,dozent,ort,datum,land,a1,a2,a3,a4,b1,b2,b3,c1,c1_txt,c2,c3,c4,c5,d1,d2,d3,d4_txt,d5_txt)  VALUES ('"
                           + boxKurs
                           + "','"
                           + boxDozent
                           + "','"
                           + boxOrt
                           + "','"
                           + spinDatum
                           + "','"
                           + auswahlland
                           + "','"
                           + auswahla1
                           + "','"
                           + auswahla2
                           + "','"
                           + auswahla3
                           + "','"
                           + auswahla4
                           + "','"
                           + auswahlb1
                           + "','"
                           + auswahlb2
                           + "','"
                           + auswahlb3
                           + "','"
                           + auswahlc1
                           + "','"
                           + tfC14
                           + "','"
                           + auswahlc2
                           + "','"
                           + auswahlc3
                           + "','"
                           + auswahlc4
                           + "','"
                           + auswahlc5
                           + "','"
                           + auswahld1
                           + "','"
                           + auswahld2
                           + "','"
                           + auswahld3 + "','" + tfD4 + "','" + tfD5 + "')");
           return pst.executeUpdate();

       } catch (SQLException e) {
           e.printStackTrace();
           return 0;

       } finally {
           if (pst != null) {
               try {
                   pst.close();
               } catch (SQLException e) {
                   e.printStackTrace();
               }
           }
       }
   }
```
das hat ja bis dato auch einwandfrei funktioniert
in der Combobox wähle ich kursnr 1.13.oder 2.15 aus sow wie die select zum laden auch definiert ist

das Resultset beim laden der combobox liefert für alle drei Spalten auch die richtigen Werte in der Konsole


----------



## Joose (30. Jan 2017)

Es ist trotzdem der falsche Weg einfach Object als Type für die Parameter festzulegen. Verwende doch den konkreten Typ den du erwartest (also zum Beispiel: int, String, double, Date, ...).
Schau dir bitte die PreparedStatements nochmal an. Du stückelst dein SQL Statement noch immer zusammen -> Gefahr von SQL Injection!

Dort wo du die `speichern` Methode aufrufst solltest du kontrollieren ob du auch wirklich das richtige (gewünschte) KursElement Objekt selektiert hast und auch von der Methode `getSelectedItem` zurück bekommst.


----------



## didi577 (30. Jan 2017)

habe noch einen Ansatz gefunden, in der Klasse KursElement sieht es so aus:

```
public class KursElement {
   
   private String kurs_id;
   private String kursnr;
   private String bezeichnung;
   
   public KursElement(String kurs_id, String kursnr, String bezeicnung) {
       
       this.kurs_id = kurs_id;
       this.kursnr = kursnr;
       this.bezeichnung = bezeicnung;
       
   }
   
   public String toString() {
       
       return kurs_id;
   }
   
   public String getKurs_Id() {
       
       return kurs_id;
   }
   
   public String getKursnr() {
       
       return kursnr;
   }
   
   public String getBezeichnung() {
       
       return bezeichnung;
   }

}
```

hier habe ich eine andere Reihenfolge im Konstruktor und 
public String toString() {

       return kurs_id;
   }

ich werde hier mal schauen...


----------



## Harry Kane (30. Jan 2017)

1. Du hast den Sinn von PreparedStatements nicht verstanden.
2. Das was du als "Struktur der db" gepostet hast, ist nicht wirklich hilfreich. Wenn du beim insert in die Tabelle "fragen" unerwartetes Verhalten bekommst, wäre es natürlich hilfreich, deren Struktur zu posten anstatt die Struktur der "kurse" Tabelle. Dann könnte man schauen, on in die "kurs" Spalte der "fragen" Tabelle wirklich die kursnr oder vielleicht doch die kurse_id (den Plural bei kurse_id finde ich auch verwirrend) gehört.
Aber jetzt bin ich raus.


----------



## Joose (30. Jan 2017)

Harry Kane hat gesagt.:


> Was du uns mit deinem letzten Beitrag sagen möchtest, erschliesst sich mir nicht.



Wenn man sich vorherige Beiträge nochmals anschaut fällt auf das er im SELECT Statement folgendes stehen hat "SELECT kursnr, kurse_id ....".
Beim Erstellen der KursElement Objekte übergibt er die Daten in der falschen Reihenfolge. Die Kursnr übergibt er als kurse_id und die kurse_id als kursnr.


----------



## didi577 (30. Jan 2017)

hab das mal gedreht:

```
public class KursElement {
   
   private String kurs_id;
   private String kursnr;
   private String bezeichnung;
   
   public KursElement(String kursnr, String kurs_id, String bezeichnung) {
       
       this.kurs_id = kursnr;
       this.kursnr = kurs_id;
       this.bezeichnung = bezeichnung;
       
   }
   
   public String toString() {
       
       return kurs_id;
   }
   
   public String getKurs_Id() {
       
       return kurs_id;
   }
   
   public String getKursnr() {
       
       return kursnr;
   }
   
   public String getBezeichnung() {
       
       return bezeichnung;
   }

}
```

er speichert trotzdem nicht die richtige Nummer


----------



## didi577 (30. Jan 2017)

die fragen Tabelle


in kurs kommt halt meistens 1 an oder ab und zu 2


----------



## Joose (30. Jan 2017)

Bitte verwende den Debugger! Kontrolliere welche KursElement Objekte erstellt werden (sind diese korrekt?)
Kontrolliere mit Hilfe des Debuggers ob wirklich das selektierte Element zurückgegeben wird und ob es die richtigen Daten enthält!

Ich hoffe dein "Bugfix" indem du die Parameterbezeichner im Konstruktor von KursElement vertauscht ist nicht ernst gemeint und war nur zum testen. Wenn du schon einen Fehler bemerkst dann behebe ihn auch richtig 
*) Passe entweder dein SELECT Statement an
*) Lies die Strings in der richtigen Reihenfolge von ResultSet aus
*) Passe den Konstruktor so an das die Bezeichner passen (es ist unlogisch das der Parameter "kursnr" dem Attribut "kurse_id" zugewiesen wird)


----------



## didi577 (30. Jan 2017)

schreiiiiiiiii


Joose hat gesagt.:


> es ist unlogisch das der Parameter "kursnr" dem Attribut "kurse_id" zugewiesen wird


das war das Speichern Problem...das hab ich echt nicht gesehen 
habe es richtig geschrieben und er speichert die richtigen kurs_id


----------



## didi577 (30. Jan 2017)

jetzt habe ich aber in der Combobox das Problem dass er nicht mehr kursnr sonder kurs_id anzeigt, die Reihenfolge beim Aufruf ist aber:

```
mysql.boxKursLaden(boxKursM, "select kursnr, kurse_id, bezeichnung from kurse ORDER BY kursnr");
```


----------



## JAVAKEK (30. Jan 2017)

Programmier doch vielleicht erstmal nen Taschenrechner


----------



## didi577 (30. Jan 2017)

haha

als ich das Projekt begann war mir nicht bewusst was da so alles kommt. jetzt bin ich kurz vorm Ziel...


----------



## JAVAKEK (30. Jan 2017)

Deine toString gibt mit Sicherheit noch die kurs_id zurück


----------



## didi577 (30. Jan 2017)

wenn ich die raus nehme wird in der Combobox package und Klassenname und @ ... geladen


----------



## JAVAKEK (30. Jan 2017)

Nix rausnehmen, ersetzten durch kursnr


----------



## didi577 (30. Jan 2017)

ok Jungs, ich gehe erstmal abkühlen

vielen vielen Dank für eure Geduld und Hilfe

ich werde morgen weiter machen


----------



## Joose (31. Jan 2017)

didi577 hat gesagt.:


> wenn ich die raus nehme wird ...


Niemand hatte was von rausnehmen gesagt ... nur dass du das richtige zurückgeben musst.
Du musst auch überlegen welche Auswirkungen die Änderung am Code hat, nicht einfach mittels try/fail ausprobieren und auf gut Glück hoffen.


----------



## didi577 (31. Jan 2017)

es funktioniert jetzt mit kursnr

vielen Dank nochmal, auch für eure Kritik

ich weiß doch das ich noch ne Menge Hausaufgaben machen muss und vor allem funktionierenden Code auch verstehen muss, ich werde jetzt erstmal eure "Meckerliste" aus diesem Beitrag abarbeiten und meinen Code bereinigen, gelernt habe ich gestern auf jeden Fall ne Menge


----------

