Nach Lektion M3.2 gibt es zwei Wege zu denselben Zeilen: das Windows-Programm mit seinem DataSet und die neue Schicht mit Entity Framework Core. Bald kommen eine Web-API und eine Blazor-Seite dazu, und für Wochen oder Monate arbeiten Frau Aydin im alten Programm und ein Pilotkunde im neuen. Beide lesen, beide schreiben, und es gibt eine Datenbank. Wer das nicht bewusst regelt, lernt die Regeln aus den Fehlern.

Diese Lektion regelt es: mit einer Schutzschicht im neuen Code, mit klaren Besitzern je Datenstück, mit einer Sicht als Naht und mit einer Methode, das Schema zu ändern, ohne eines der Programme zu brechen. Die Datenarchitektur dahinter, also wann man Datenbanken teilt und wann nicht, steht in K4, Modul 4.13. Hier geht es um den Übergang.

Was geht schief, wenn zwei Programme eine Datenbank teilen

Die Fehlerbilder lassen sich vorher aufzählen. Jedes ist im Auftragsbuch vorhanden oder entsteht in den nächsten Wochen:

Fehlerbild Beispiel im Auftragsbuch Gegenmittel
Beide ändern dieselbe Zeile Frau Aydin ändert den Termin im alten Programm, der Pilotkunde die Notiz im neuen Sperre in beiden Programmen (Lektion M3.2)
Das neue Programm schreibt etwas, das das alte nicht lesen kann Status „Abgerechnet“ ohne Rechnungsnummer: Der Export des alten Programms liest (string)auftrag["Rechnungsnummer"] und scheitert mit einer Ausnahme Schutzschicht beim Schreiben
Eine Schemaänderung bricht das andere Programm eine neue Pflichtspalte ohne Standardwert: jedes INSERT des alten Programms scheitert Expand and Contract
Eine Regel steht nur an einem Ort der Trigger, der den Wartungsplan weiterrückt, wird vom neuen Code nie aufgerufen und von niemandem ersetzt Besitzer festlegen, Test
Die Wörter des alten Systems sickern in das neue Sanitaet ohne Umlaut, Status als Zeichenkette, Termin als nullbares Datum Übersetzung an einer Stelle
Niemand weiß, wer was darf jeder schreibt überall, weil es technisch geht Datenbankrechte, Dokument

Die beiden mittleren Zeilen sind die gefährlichsten: Sie brechen leise, und niemand denkt an sie, solange nichts schiefgeht. Wie leise, zeigt eine Probe. Das alte Programm schreibt Aufträge mit einem INSERT, das die Spalten aus seiner SELECT-Liste nennt. Fügt man der Tabelle eine Spalte hinzu, kommt es auf die Art der Spalte an. Die Probe läuft in der Testdatenbank, in einer Transaktion, die zurückgerollt wird:

PowerShell
$insert = "INSERT dbo.Auftraege (KundeId, WartungId, Titel, Art, Status, Termin, Stunden, Material, Rechnungsnummer) VALUES (1, NULL, N'Probe', N'Heizung', N'Neu', NULL, 0, 0, NULL);"
sqlcmd -S '(localdb)\MSSQLLocalDB' -d AuftragsbuchTest -E -W -Q "BEGIN TRAN; ALTER TABLE dbo.Auftraege ADD Prioritaet int NULL; $insert SELECT N'nullbar: INSERT ok' AS Ergebnis; ROLLBACK;"
sqlcmd -S '(localdb)\MSSQLLocalDB' -d AuftragsbuchTest -E -W -Q "BEGIN TRAN; ALTER TABLE dbo.Auftraege ADD Prioritaet int NOT NULL CONSTRAINT DF_Prio DEFAULT (0); $insert SELECT N'Pflicht mit Standardwert: INSERT ok' AS Ergebnis; ROLLBACK;"
sqlcmd -S '(localdb)\MSSQLLocalDB' -d AuftragsbuchTest -E -W -Q "BEGIN TRAN; ALTER TABLE dbo.Auftraege ADD Prioritaet int NOT NULL CONSTRAINT DF_Prio DEFAULT (0); ALTER TABLE dbo.Auftraege DROP CONSTRAINT DF_Prio; $insert ROLLBACK;"
Ergebnis
--------
nullbar: INSERT ok

Ergebnis
--------
Pflicht mit Standardwert: INSERT ok

Msg 515, Level 16, State 2, Server ..., Line 1
Cannot insert the value NULL into column 'Prioritaet', table 'AuftragsbuchTest.dbo.Auftraege'; column does not allow nulls. INSERT fails.
The statement has been terminated.

(In der dritten Zeile steht eine Pflichtspalte ohne Standardwert, wie sie ein neues Programm gern anlegt: Man legt sie mit Standardwert an, damit die Tabelle sich ändern lässt, und nimmt ihn danach weg. Das alte Programm kennt die Spalte nicht und kann sie nicht füllen. Der Wortlaut der Meldung hängt von der Sprache der SQL-Server-Installation ab.)

Die Probe liefert die Faustregel der ganzen Lektion: Eine Änderung, bei der das alte Programm nichts ändern muss, ist rückwärtsverträglich. Alles andere bricht es.