{"id":55000121,"date":"2018-02-01T00:00:00","date_gmt":"2020-03-27T19:30:39","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=121"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"EDM_Code_First__Datenbank_erweitern","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/EDM_Code_First__Datenbank_erweitern\/","title":{"rendered":"EDM: Code First &#8211; Datenbank erweitern"},"content":{"rendered":"<p><b>Im Artikel &#8220;EDM: Der Code First-Ansatz&#8221; haben wir uns angesehen, wie Sie auf Basis eines frisch erstellten Entity Data Models eine Datenbank samt den n&ouml;tigen Tabellen erstellen k&ouml;nnen &#8211; und zwar automatisch beim ersten Zugriff auf die noch nicht vorhandene Datenbank. Nun gehen wir einen Schritt weiter und zeigen, wie Sie auch noch &Auml;nderungen am Entity Data Model auf bestehende Datenbanken mit &auml;lterem Versionsstand &uuml;bertragen und somit ein kombiniertes Update von Anwendung und Datenbank ausliefern k&ouml;nnen.<\/b><\/p>\n<h2>Aktualisierungen am bestehenden Datenmodell<\/h2>\n<p>Wir haben w&auml;hrend der Entwicklung der Anwendung, wie wir es im Artikel EDM: Der Code First-Ansatz gelernt haben, die Freiheit, nach Lust und Laune die Zieldatenbank zu l&ouml;schen und neu zu erstellen. Wohlgemerkt: w&auml;hrend der Entwicklung! Sobald die Datenbank jedoch einmal mit Daten gef&uuml;llt ist oder sogar beim Kunden l&auml;uft, wollen Sie Aktualisierungen am Datenmodell sicher etwas eleganter und ohne Datenverlust &uuml;bermitteln. Auch dazu bietet Code First M&ouml;glichkeiten.<\/p>\n<p>Um Migrationen mit Code First durchzuf&uuml;hren, also die &Auml;nderungen erst am bestehenden Modell der Entit&auml;ten durchzuf&uuml;hren und diese dann auf die Tabellen der Datenbank zu &uuml;bertragen, m&uuml;ssen wir zun&auml;chst die Migrationsfunktion aktivieren.<\/p>\n<p>Dazu ben&ouml;tigen wir die Paket-Manager-Konsole, die Sie mit dem Men&uuml;befehl Ansicht|Weitere Fenster|Paket-Manager-Konsole einblenden. Ist dieser eingeblendet, w&auml;hlen Sie oben rechts unter Standardprojekte den Namen des betroffenen Projekts aus, in diesem Fall CodeFirst. Dann geben Sie den folgenden Befehl ein:<\/p>\n<pre>PK&gt; enable-migrations<\/pre>\n<p>Das Ergebnis finden Sie in Bild 1 vor.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/pic_121_009.png\" alt=\"Aktivieren der Migrationsfunktion\" width=\"649,559\" height=\"230,2008\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Aktivieren der Migrationsfunktion<\/span><\/b><\/p>\n<p>Im Projekt haben sich nun einige &Auml;nderungen ergeben, die Sie direkt im Projektmappen-Explorer ablesen k&ouml;nnen. Dort finden Sie nun n&auml;mlich einen neuen Ordner namens Migrations (siehe Bild 2). Dieser enth&auml;lt eine Datei namens Configuration.vb.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/pic_121_010.png\" alt=\"Die neue Konfigurationsdatei\" width=\"424,7115\" height=\"348,8391\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Die neue Konfigurationsdatei<\/span><\/b><\/p>\n<p>Diese Datei enth&auml;lt vor allem die Seed-Methode. Dieser k&ouml;nnen Sie Anweisungen zum Schreiben von Daten in die Tabellen der Datenbank hinzuf&uuml;gen. Die Seed-Methode wird sp&auml;ter beim Update des Datenbank-Backends ausgel&ouml;st. Deshalb f&uuml;gen wir beispielsweise die folgenden Codezeilen zu dieser Methode in der Klasse Configuration.vb hinzu:<\/p>\n<pre>Namespace Migrations\r\n     Friend NotInheritable Class Configuration \r\n         Inherits DbMigrationsConfiguration(Of Wordgenerator)\r\n         <span style=\"color:blue;\">Public <\/span>Sub New()\r\n             AutomaticMigrationsEnabled = <span style=\"color:blue;\">False<\/span>\r\n             ContextKey = \"CodeFirst.Wordgenerator\"\r\n         End Sub\r\n         Protected Overrides Sub Seed(context<span style=\"color:blue;\"> As <\/span>Wordgenerator)\r\n             <span style=\"color:blue;\">Dim <\/span>anrede<span style=\"color:blue;\"> As <\/span><span style=\"color:blue;\">New<\/span> Anrede <span style=\"color:blue;\">With<\/span> {.Bezeichnung = \"Herr\"}\r\n             context.Anreden.AddOrUpdate(Function(p) p.Bezeichnung, anrede)\r\n             anrede = <span style=\"color:blue;\">New<\/span> Anrede <span style=\"color:blue;\">With<\/span> {.Bezeichnung = \"Frau\"}\r\n             context.Anreden.AddOrUpdate(Function(p) p.Bezeichnung, anrede)\r\n             anrede = <span style=\"color:blue;\">New<\/span> Anrede <span style=\"color:blue;\">With<\/span> {.Bezeichnung = \"Firma\"}\r\n             context.Anreden.AddOrUpdate(Function(p) p.Bezeichnung, anrede)\r\n         End Sub\r\n     End Class\r\nEnd Namespace<\/pre>\n<p>Damit wollen wir sicherstellen, dass zumindest die grundlegenden Daten der Anwendung, n&auml;mlich die Anreden, bereits in die Tabelle <b>Anreden <\/b>geschrieben werden &#8211; hier also die Datens&auml;tze mit den Werten <b>Herr<\/b>, <b>Frau <\/b>und <b>Firma <\/b>im Feld <b>Bezeichnung<\/b>.<\/p>\n<p>Anschlie&szlig;end geben Sie einen weiteren Befehl in den Bereich <b>Paket-Manager-Konsole <\/b>ein (siehe Bild 3):<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/pic_121_011.png\" alt=\"Initiale Migration\" width=\"649,559\" height=\"209,2417\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Initiale Migration<\/span><\/b><\/p>\n<pre>PM&gt; Add-Migration Initial<\/pre>\n<p>Dadurch wird eine weitere Datei zum Ordner <b>Migrations <\/b>hinzugef&uuml;gt, diesmal nach dem Schema <b>201802121707380_Initial.vb<\/b>. Diese Klasse enth&auml;lt eine Methode namens <b>Up<\/b>, die drei <b>CreateTable<\/b>-Anweisungen enth&auml;lt, mit denen die Tabellen entsprechend der Entit&auml;ten <b>Anrede<\/b>, <b>Adresse <\/b>und <b>Brief <\/b>erstellt werden &#8211; hier in gek&uuml;rzter Form nur mit den Anweisungen f&uuml;r die Tabelle <b>Anreden<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Overrides Sub Up()\r\n     ...\r\n     CreateTable(\r\n         \"dbo.Anreden\",\r\n         Function(c) <span style=\"color:blue;\">New<\/span> <span style=\"color:blue;\">With<\/span>\r\n             {\r\n                 .ID = c.Int(nullable := False, identity := <span style=\"color:blue;\">True<\/span>),\r\n                 .Bezeichnung = c.String()\r\n             }) _\r\n         .PrimaryKey(Function(t) t.ID)\r\n     ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Zus&auml;tzlich enth&auml;lt die Klasse noch eine Methode namens <b>Down<\/b>, welche die bestehenden Schl&uuml;ssel, Indizes und Tabellen l&ouml;scht:<\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Overrides Sub Down()\r\n     DropForeignKey(\"dbo.Briefe\", \"Adresse_ID\", \"dbo.Adressen\")\r\n     DropForeignKey(\"dbo.Adressen\", \"Anrede_ID\", \"dbo.Anreden\")\r\n     DropIndex(\"dbo.Briefe\", <span style=\"color:blue;\">New<\/span> String() { \"Adresse_ID\" })\r\n     DropIndex(\"dbo.Adressen\", <span style=\"color:blue;\">New<\/span> String() { \"Anrede_ID\" })\r\n     DropTable(\"dbo.Briefe\")\r\n     DropTable(\"dbo.Anreden\")\r\n     DropTable(\"dbo.Adressen\")\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Au&szlig;erdem setzen Sie im gleichen Bereich noch den folgenden Befehl ab:<\/p>\n<pre>PM&gt; Update-Database<\/pre>\n<p>Damit rufen Sie zun&auml;chst die Methoden der Klasse <b>201802121707380_Initial.vb <\/b>auf, welche die Datenbank und das Datenmodell anlegt, wenn diese noch nicht vorhanden ist, und dann mit der <b>Seed<\/b>-Methode die initialen Daten in die Tabelle <b>Anreden <\/b>schreibt.<\/p>\n<h2>&Auml;nderungen am Datenmodell<\/h2>\n<p>Nun nehmen wir eine kleine &Auml;nderung am Datenmodell vor. Wohlgemerkt: Die aktuelle Version, die durch die Datei <b>201802121707380_Initial.vb <\/b>beschrieben wird, haben wir durch die <b>Update-Database<\/b>-Methode in der <b>Paket-Manager-Konsole <\/b>bereits angewendet und damit eine neue Datenbank erzeugt. Nun f&uuml;gen wir der Entit&auml;t <b>Anreden <\/b>eine Eigenschaft namens <b>Briefanrede <\/b>hinzu:<\/p>\n<pre>&lt;Table(\"Anreden\")&gt;\r\n<span style=\"color:blue;\">Public Class<\/span> Anrede\r\n     <span style=\"color:blue;\">Public <\/span>Property ID<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Public <\/span>Property Bezeichnung<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Public <\/span>Property Briefanrede<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Public <\/span>Property Adressen<span style=\"color:blue;\"> As <\/span>ICollection(Of Adresse)\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p>Nun rufen wir wieder eine neue Anweisung in der <b>Paket-Manager-Konsole <\/b>auf:<\/p>\n<pre>add-migration add_Anrede_Briefanrede<\/pre>\n<p>Dies erstellt eine neue VB-Klasse namens <b>201802121730445_add_Anrede_Briefanrede.vb<\/b>, welche die &Auml;nderungen im Datenmodell seit der letzten &Auml;nderung enth&auml;lt, und die wieder in Form der beiden Methoden <b>Up <\/b>und <b>Down <\/b>eingetragen werden. Das sieht dann so aus:<\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Partial Class add_Anrede_Briefanrede\r\n     Inherits DbMigration\r\n     <span style=\"color:blue;\">Public <\/span>Overrides Sub Up()\r\n         AddColumn(\"dbo.Anreden\", \"Briefanrede\", Function(c) c.String())\r\n     End Sub\r\n     <span style=\"color:blue;\">Public <\/span>Overrides Sub Down()\r\n         DropColumn(\"dbo.Anreden\", \"Briefanrede\")\r\n     End Sub\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<div class=\"rcp_restricted\"><p><span style=\"color: #ff0000;\">M&ouml;chten Sie weiterlesen? Dann l&ouml;sen Sie Ihr Ticket!<\/span><br \/>\n<span style=\"color: #ff0000;\">Hier geht es zur Bestellung des Jahresabonnements des Magazins <strong>Visual Basic Entwickler<\/strong>:<\/span><br \/>\n<span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/shop.minhorst.com\/magazine\/363\/visual-basic-entwickler-jahresabonnement?c=77\">Zur Bestellung ...<\/a><\/span><br \/>\n<span style=\"color: #ff0000;\">Danach greifen Sie sofort auf <strong>alle rund 200 Artikel<\/strong> unseres Angebots zu - auch auf diesen hier!<\/span><br \/>\n<span style=\"color: #000000;\">Oder haben Sie bereits Zugangsdaten? Dann loggen Sie sich gleich hier ein:<\/span><\/p>\n<\/div>\n\n\t\n\t<form id=\"rcp_login_form\"  class=\"rcp_form\" method=\"POST\" action=\"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000121\/\">\n\n\t\t\n\t\t<fieldset class=\"rcp_login_data\">\n\t\t\t<p>\n\t\t\t\t<label for=\"rcp_user_login\">Username or Email<\/label>\n\t\t\t\t<input name=\"rcp_user_login\" id=\"rcp_user_login\" class=\"required\" type=\"text\"\/>\n\t\t\t<\/p>\n\t\t\t<p>\n\t\t\t\t<label for=\"rcp_user_pass\">Password<\/label>\n\t\t\t\t<input name=\"rcp_user_pass\" id=\"rcp_user_pass\" class=\"required\" type=\"password\"\/>\n\t\t\t<\/p>\n\t\t\t\t\t\t<p>\n\t\t\t\t<input type=\"checkbox\" name=\"rcp_user_remember\" id=\"rcp_user_remember\" value=\"1\"\/>\n\t\t\t\t<label for=\"rcp_user_remember\">Remember me<\/label>\n\t\t\t<\/p>\n\t\t\t<p class=\"rcp_lost_password\"><a href=\"\/data\/wp\/v2\/posts\/55000121?rcp_action=lostpassword\"><\/a><\/p>\n\t\t\t<p>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_action\" value=\"login\"\/>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_redirect\" value=\"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000121\/\"\/>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_login_nonce\" value=\"34aae43e8a\"\/>\n\t\t\t\t<input id=\"rcp_login_submit\" class=\"rcp-button\" type=\"submit\" value=\"Login\"\/>\n\t\t\t<\/p>\n\t\t\t\t\t<\/fieldset>\n\n\t\t\n\t<\/form>\n<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im Artikel &#8220;EDM: Der Code First-Ansatz&#8221; haben wir uns angesehen, wie Sie auf Basis eines frisch erstellten Entity Data Models eine Datenbank samt den n&ouml;tigen Tabellen erstellen k&ouml;nnen &#8211; und zwar automatisch beim ersten Zugriff auf die noch nicht vorhandene Datenbank. Nun gehen wir einen Schritt weiter und zeigen, wie Sie auch noch &Auml;nderungen am Entity Data Model auf bestehende Datenbanken mit &auml;lterem Versionsstand &uuml;bertragen und somit ein kombiniertes Update von Anwendung und Datenbank ausliefern k&ouml;nnen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[66012018,662018,44000024,44000021,44000004],"tags":[],"yst_prominent_words":[],"class_list":["post-55000121","post","type-post","status-publish","format-standard","hentry","category-66012018","category-662018","category-Berichte_und_Reporting","category-Entity_Framework","category-Loesungen"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000121","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000121"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000121\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000121"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000121"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000121"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000121"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}