Datenbankbeispiel 5


Einleitung

Um diese Anleitung nicht zu lang werden zu lassen, schreibe ich immer nur die Dinge auf, die verändert werden müssen. Bei Codeabschnitten werden die Teile, die von mir verändert wurden fett geschrieben.

Beispiel

Aufgabe

Es sollten vor Beginn dieses Projekts die Maßnahmen getroffen werden, die im Kapitel "Datenbankzugriff Vorbereitung" angegeben sind.



Die Datenbank "Nordwind" enthält unter anderem die Tabellen
  • "Bestellungen"
  • "Kunden"
  • "Personal"
Erstellen sie ein Programm, welches in einem CTreeCtrl in oberster Ebene jeweils ein Bestelldatum anzeigt, zu dem Bestellungen vorliegen.
In der Ebene darunter werden die Firmen der einzelnen Bestellungen angezeigt.
Bei Anklicken einer solchen Firma wird in einem modalen Dialog angezeigt:
  • Firmenname (Kunde)
  • Land (Kunde)
  • Bestelldatum (Bestellung
  • Vorname (Personal)
  • Nachname (Personal)

Lösung in Prosa

  1. Zuerst einmal ein neues Projekt anlegen:
  2. Zeichnen des Dialogs:
    Es wird nur ein TreeControl benötigt.


    Um die Linien und Schaltflächen beim TreeControl zu erhalten, braucht man nur die Eigenschaften zu editieren:
  3. Es wird noch eine Membervariable für den TreeControl benötigt.
    Dazu muss der Klassenassistent geöffnet werden.
  4. Nun müssen die restlichen Tabellen eingebunden werden und zwar Kunden und Personal. Dazu den Klassenassistent öffnen.
    Dann alle Membervariablen für die Spalten in der Klasse Cdb5Set löschen und auf den Button "Spalten aktualisieren" drücken.

    Nun ist die Datenbank noch einmal auszuwählen.

    Hier können nun alle Tabellen markiert werden.

  5. Es müssen nun im Klassenassistent für die benötigten Spalten in den Tabellen, Variable angelegt werden.
    Benötigt werden:
  6. Nun müssen noch die Namen der Tabellen in den nachfolgenden Funktionsaufruf eingefügt werden.
    CString CDb5Set::GetDefaultSQL()
    {
    	return _T("[Bestellungen],[Personal],[Kunden]");
    }
          
  7. Um beim Programmstart das TreeControl mit Elementen zu füllen, eignet sich die Methode OnInitalUpdate am Besten.
    void CDb5View::OnInitialUpdate()
    {
    	m_pSet = &GetDocument()->m_db5Set;
    	CRecordView::OnInitialUpdate();
    	GetParentFrame()->RecalcLayout();
    	ResizeParentToFit();
    
    	// Nach Bestelldatum sortieren
    	m_pSet->m_strSort = "[Bestellungen].[Bestelldatum]";
    	// Um zu verhindern, dass die Datenbank einfach jeden Datensatz mit jedem
    	// verknüpft (Natural Join), müssen die Verknüpfungen ausgewählt werden,
    	// die einen Sinn ergeben
    	m_pSet->m_strFilter = "[Bestellungen].[Personal-Nr]=[Personal].[Personal-Nr] AND [Bestellungen].[Kunden-Code]=[Kunden].[Kunden-Code]";
    	// Erneutes Laden der Tabellen, um die Sortierung und den Filter
    	// einzuschalten.
    	m_pSet->Requery();
    
    	CTime oldtime;
    	// Solange weitere Datensätze vorhanden
    	while (!m_pSet->IsEOF())
    	{
    		// Zum merken des aktullen Root-Items (Item oberster Ebene)
    		HTREEITEM parent;
    		
    		// Nur wenn neues Root Item gebraucht wird
    		if (oldtime != m_pSet->m_Bestelldatum)
    		{
    			// Neues merken
    			oldtime = m_pSet->m_Bestelldatum;
    			// Neues anlegen
    			parent = m_tree.InsertItem(m_pSet->m_Bestelldatum.Format("%d.%m.%y"));
    		}
    		// Firmenname als Unterelement des aktuellen parent einfügen
    		HTREEITEM item = m_tree.InsertItem(m_pSet->m_Firma,parent);
    		// Merken der eindeutigen Bestellnummer beim Item
    		// damit es später beim Klick Event leichter wieder identifiziert werden kann
    		m_tree.SetItemData(item,m_pSet->m_BestellNummer);
    		// Zum nächsten Datensatz springen
    		m_pSet->MoveNext();
    	}
    }
          
  8. Dem Programm fehlt nun nur noch ein Dialog in dem bei einem Klick auf einen Eintrag dessen Informationen angezeigt werden. Dazu in den Ressourcen einen neuen Dialog einfügen.
  9. Um eine Klasse für diesen Dialog anzulegen braucht nur der Klassenassistent geöffnet werden. Die Frage eine Klasse für den Dialog zu erstellen kann man nun mit ja beantworten. Darauf kann man in einem weiteren Dialog den Klassennamen einstellen.
  10. Für die Eingabefelder müssen noch Variable erstellt werden.
  11. Damit die Klasse benutzt werden kann muss sie erst in Datei db5view.cpp eingebunden werden.
    // db5View.cpp : Implementierung der Klasse CDb5View
    //
    
    #include "stdafx.h"
    #include "db5.h"
    
    #include "db5Set.h"
    #include "db5Doc.h"
    #include "db5View.h"
    
    #include "Dialog.h"
    			
  12. Erstellen eines Handlers für das Anklicken eines Elements im TreeControl.
    Die beste Wahl ist hier TVN_SELCHANGED, weil NM_CLICK nicht zielführend ist, weil man nicht erfährt, auf welches Item gedrückt wurde.
  13. Code für den Handler.
    void CDb5View::OnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult) 
    {
    	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
    
    	if (pNMTreeView != NULL)
    	{
    		if (pNMTreeView->itemNew.lParam != NULL)
    		{
    			// Um Bestellung zu finden
    			m_pSet->m_strFilter.Format("[Bestellungen].[Bestell-Nr] = %d", pNMTreeView->itemNew.lParam);
    			// Um jedes mit jedem Verknüpfung zu verhindern
    			m_pSet->m_strFilter += " AND [Bestellungen].[Personal-Nr]=[Personal].[Personal-Nr] AND [Bestellungen].[Kunden-Code]=[Kunden].[Kunden-Code]";
    			m_pSet->Requery();
    
    			Dialog dia;
    			dia.m_firma = m_pSet->m_Firma;
    			dia.m_land = m_pSet->m_Kunde_Land;
    			dia.m_bestelldatum = m_pSet->m_Bestelldatum.Format("%d.%m.%y");
    			dia.m_vorname = m_pSet->m_Vorname;
    			dia.m_nachname = m_pSet->m_Nachname;
    			dia.DoModal();
    		}
    	}
    	*pResult = 0;
    }
          
  14. Fertig