Der erste Meilenstein bringt die Kontakte fertig. Dafür brauchen Sie fast alles aus den Modulen davor auf einmal: eine Regel im Kern (Modul 1.6 und 2.3), eine Tabelle mit Migration (2.4), eine Seite ohne Skript (2.5), eine Rechteentscheidung (2.6) und Tests auf allen Ebenen (2.7). Neu ist kaum etwas. Neu ist, dass alles in einem Stück zusammenpassen muss.

Die Lektion folgt dem Schnitt aus Lektion 2.11.1:

Pull Request Branch Bringt Wo in dieser Lektion
1 feature/m1-company-model Firmen als eigene Einträge Abschnitt „Pull Request 1“
2 feature/m1-company-migration die Firmentexte werden zu Firmen Abschnitt „Pull Request 2“
3 feature/m1-tags Schlagwörter Übung 1
4 feature/m1-search Suche, Filter und Seiten Abschnitt „Pull Request 4“
5 feature/m1-delete Löschen mit Rückfrage, nur für die Leitung Übung 2

Die Abnahmekriterien stehen in Ihren Issues aus Lektion 2.11.1. Die Testnamen in dieser Lektion sind die aus der Lösung dort.

Wo die Kladde steht

In K1 war die Firma ein Text am Kontakt, und das ist sie in den meisten Kladden bis heute: eine Spalte Company in der Tabelle Contacts. Daraus entstehen bekannte Probleme. „Kranich Bau“, „kranich bau“ und „Kranich Bau“ mit zwei Leerzeichen sind drei verschiedene Texte, und eine Liste aller Kontakte einer Firma findet nur die, die genau gleich geschrieben sind.

Die Beispiele dieser Lektion gehen von diesem Stand aus:

  • Contact in Kladde.Core hat Id, Name, Email (das Wertobjekt EmailAddress) und den Text Company.
  • Die Kontaktliste /kontakte sucht und blättert über die Adresse der Seite, mit q für den Suchtext und seite für die Seite (Lektion 2.5.4). Das Filterskript aus Lektion 2.5.11 umschließt Formular und Liste als Custom Element.
  • DELETE /api/contacts/{id} ist seit Lektion 2.6.3 der Leitung vorbehalten.
  • Die Rollen heißen Buero und Leitung und stehen seit Lektion 2.6.3 als Konstanten KladdeRoles.Office und KladdeRoles.Management in Kladde.Web.Auth.

Die Lösungen der Module 2.4 bis 2.6 sind an einigen Stellen schon weiter oder anders gebaut. Übertragen Sie die Schritte dann so:

  • Schlagwörter stehen seit Lektion 2.4.6 in der Tabelle ContactTags, eine Zeile je Wort. Dabei bleibt es; Pull Request 3 bringt nur die neue Regel. In der Suche wird aus c.Tags.Contains(tag) dann db.ContactTags.Any(t => t.ContactId == c.Id && t.Tag == tag), und die Schlagwörter einer Zeile liest die Projektion wie in Lektion 2.4.9.
  • Die E-Mail-Adresse bildet Lektion 2.4.6 mit einem Wertkonverter ab, die Beispiele hier als Complex Type mit derselben Spalte Email. Mit dem Wertkonverter vergleicht die Suche die ganze Adresse, wie ContactDirectory in Lektion 2.4.9; lassen Sie den Konverter dann, wie er ist, denn auf seiner Spalte liegt der eindeutige Index UX_Contacts_Email.
  • Suche und Seiten hat ContactDirectory schon seit den Lektionen 2.4.9 und 2.5.4. Pull Request 4 erweitert dann diesen Dienst um Firma und Schlagwort, statt einen zweiten danebenzustellen. Die Seite in Pull Request 4 zeigt nur, was für Firma und Schlagwort dazukommt; das Custom Element des Filterskripts und die Live-Region aus Lektion 2.5.11 bleiben in Ihrer Seite stehen.
  • Die Rückfrage zum Löschen unter /kontakte/{id}/loeschen gibt es seit Übung 3 von Lektion 2.6.3, dort mit der Richtlinie KladdePolicies.Management. Übung 2 ergänzt sie um das, was ihr noch fehlt.
  • Die Nummer eines Kontakts vergibt in den Lösungen die Kladde selbst (ValueGeneratedNever, Lektion 2.4.6), nicht die Datenbank.

Heißen Ihre Dateien, Klassen oder Ordner anders, behalten Sie Ihre Namen und übertragen Sie die Schritte.