In diesem fünften und fortgeschrittenen Datenbank-Tutorial zeige ich, wie man mit Visual C++ und MFC mehrere Datenbanktabellen verknüpft und die Ergebnisse in einer hierarchischen Baumstruktur anzeigt. 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.



CRecordView auswählen

CTreeCtrl für den Zugriff benötigt.
CDb5Set löschen
und auf "Spalten aktualisieren" drücken.

CString CDb5Set::GetDefaultSQL()
{
return _T("[Bestellungen],[Personal],[Kunden]");
}
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 jeden Datensatz mit jedem verknüpft (Cross Join),
// müssen sinnvolle Verknüpfungen angegeben werden
m_pSet->m_strFilter = "[Bestellungen].[Personal-Nr]=[Personal].[Personal-Nr] "
"AND [Bestellungen].[Kunden-Code]=[Kunden].[Kunden-Code]";
// Erneutes Laden der Tabellen, um Sortierung und Filter zu aktivieren
m_pSet->Requery();
CTime oldtime;
// Alle Datensätze durchlaufen
while (!m_pSet->IsEOF())
{
// Zum Merken des aktuellen Root-Items (oberste Ebene)
HTREEITEM parent;
// Nur wenn neues Root Item benötigt wird (neues Datum)
if (oldtime != m_pSet->m_Bestelldatum)
{
// Neues Datum merken
oldtime = m_pSet->m_Bestelldatum;
// Neues Parent-Element im TreeControl 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);
// Bestellnummer als Item-Daten speichern für spätere Identifikation
m_tree.SetItemData(item, m_pSet->m_BestellNummer);
// Zum nächsten Datensatz springen
m_pSet->MoveNext();
}
}
// db5View.cpp : Implementierung der Klasse CDb5View // #include "stdafx.h" #include "db5.h" #include "db5Set.h" #include "db5Doc.h" #include "db5View.h" #include "DetailDialog.h" // Einbindung der Dialogklasse
TVN_SELCHANGED, da NM_CLICK nicht zielführend ist
(man erfährt nicht, auf welches Item gedrückt wurde).
void CDb5View::OnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
if (pNMTreeView != NULL)
{
// Überprüfen, ob ein gültiges Item mit Daten ausgewählt wurde
if (pNMTreeView->itemNew.lParam != NULL)
{
// Filter für spezifische Bestellung setzen
m_pSet->m_strFilter.Format("[Bestellungen].[Bestell-Nr] = %d",
pNMTreeView->itemNew.lParam);
// JOIN-Bedingungen hinzufügen, um Cross Join zu verhindern
m_pSet->m_strFilter += " AND [Bestellungen].[Personal-Nr]=[Personal].[Personal-Nr] "
"AND [Bestellungen].[Kunden-Code]=[Kunden].[Kunden-Code]";
// Datensatz mit Filter laden
m_pSet->Requery();
// Dialog erstellen und mit Daten füllen
CDetailDialog 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;
// Dialog modal anzeigen
dia.DoModal();
}
}
*pResult = 0;
}