{"id":55000170,"date":"2019-04-01T00:00:00","date_gmt":"2020-03-27T19:36:42","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=170"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"EDM_fuer_bestehende_Datenbank_mit_Code_First_","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/EDM_fuer_bestehende_Datenbank_mit_Code_First_\/","title":{"rendered":"EDM f&uuml;r bestehende Datenbank mit Code First"},"content":{"rendered":"<p><b>Wenn Sie ein Entity Data Model mit der Vorlage &#8220;Code First aus Datenbank&#8221; auf Basis einer bestehenden Datenbank erstellen, haben Sie vielleicht Pech und die Namen der Tabellen der Datenbank und der enthaltenen Felder lauten nicht so, wie Sie die Entit&auml;tsklassen, die DbSet-Elemente und die Eigenschaften der Klassen nennen m&ouml;chten. Dann haben Sie verschiedene M&ouml;glichkeiten: Zum Beispiel k&ouml;nnen Sie die Bezeichnungen in der Datenbank anpassen. Das geht aber oft nicht, weil vielleicht noch andere Frontends auf die gleiche Datenbank zugreifen. Dann haben Sie noch die M&ouml;glichkeit, die Bezeichnungen von Datenbank und Entity Data Model so zu mappen, dass beide Seiten zufrieden sind. Wie letzteres gelingt, zeigen wir im vorliegenden Artikel am Beispiel der S&uuml;dsturm-Datenbank.<\/b><\/p>\n<h2>Einfaches Beispiel: tblFotos<\/h2>\n<p>Wir starten mit einem sehr einfachen Beispiel, n&auml;mlich der Tabelle <b>tblFotos<\/b>. Diese haben wir als Tabelle zum Speichern von Fotos erstellt, die mit einer PowerApp &uuml;ber das Smartphone aufnehmen wollen. Dabei haben wir die Tabelle leichtsinnigerweise <b>tblFotos <\/b>genannt statt einfach <b>Fotos <\/b>ohne Pr&auml;fix. Wenn wir nun ein Entity Data Model erstellen, erhalten wir f&uuml;r die Klasse <b>FotoverwaltungContext.db <\/b>etwa den folgenden Code:<\/p>\n<pre>Imports System.ComponentModel.DataAnnotations.Schema\r\nPartial Public Class FotoverwaltungContext\r\n     Inherits DbContext\r\n     <span style=\"color:blue;\">Public <\/span>Sub New()\r\n         MyBase.New(\"name=FotoverwaltungContext\")\r\n     End Sub\r\n     <span style=\"color:blue;\">Public <\/span>Overridable Property tblFotos<span style=\"color:blue;\"> As <\/span>DbSet(Of tblFotos)\r\n     Protected Overrides Sub OnModelCreating(ByVal modelBuilder<span style=\"color:blue;\"> As <\/span>DbModelBuilder)\r\n     End Sub\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p>Hier h&auml;tten wir gern den Namen der Property f&uuml;r das <b>DbSet <\/b>so ge&auml;ndert, dass es <b>Fotos <\/b>statt <b>tblFotos <\/b>hei&szlig;t und Elemente des Typs <b>Foto <\/b>enth&auml;lt (die auch noch <b>tblFotos <\/b>hei&szlig;en). In der Entit&auml;tsklasse <b>tblFotos <\/b>geht es so weiter. Diese hat nach dem Erstellen des Entity Data Models den folgenden Code erhalten:<\/p>\n<pre>Imports System.ComponentModel.DataAnnotations\r\nImports System.ComponentModel.DataAnnotations.Schema\r\nPartial Public Class tblFotos\r\n     <span style=\"color:blue;\">Public <\/span>Property ID<span style=\"color:blue;\"> As Integer<\/span>\r\n     &lt;Column(TypeName:=\"image\")&gt;\r\n     &lt;Required&gt;\r\n     <span style=\"color:blue;\">Public <\/span>Property Foto<span style=\"color:blue;\"> As Byte<\/span>()\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p>Wir wollen dies Schritt f&uuml;r Schritt so anpassen, dass wir mit einer Konstruktor-Methode f&uuml;r das Fenster <b>MainWindow <\/b>wie der folgenden auf die Daten zugreifen k&ouml;nnen:<\/p>\n<pre><span style=\"color:blue;\">Class<\/span> MainWindow\r\n     <span style=\"color:blue;\">Public <\/span>Sub New()\r\n         <span style=\"color:blue;\">Dim <\/span>dbContext<span style=\"color:blue;\"> As <\/span>FotoverwaltungContext\r\n         dbContext = <span style=\"color:blue;\">New<\/span> FotoverwaltungContext\r\n         <span style=\"color:blue;\">Dim <\/span>foto<span style=\"color:blue;\"> As <\/span>Foto\r\n         foto = dbContext.Fotos.First()\r\n         MessageBox.Show(foto.ID.ToString())\r\n     End Sub\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p>Wir wollen also ein <b>DbSet <\/b>namens <b>Fotos <\/b>verwenden und damit auf Elemente des Typs <b>Foto <\/b>zugreifen. Dazu m&uuml;ssen wir dem Entity Data Model auf irgendeine Weise mitteilen, dass es das <b>DbSet <\/b>namens <b>Fotos <\/b>auf die Tabelle <b>tblFotos <\/b>mappen soll und die Klasse <b>Foto <\/b>auf die einzelnen Datens&auml;tze.<\/p>\n<h2>Mapping in der Methode OnModelCreating<\/h2>\n<p>Der richtige Ort f&uuml;r ein solches Mapping ist die Methode <b>OnModelCreating<\/b>, die beim Erstellen des Entity Data Models auf Basis der Vorlage <b>Code First aus Datenbank <\/b>automatisch in der Klasse <b>FotoverwaltungContext <\/b>angelegt wurde. Der erste Schritt ist das Umbenennen der Klasse <b>tblFotos <\/b>in <b>Foto<\/b>. Das erledigen wir ganz einfach, indem wir den entsprechenden Eintrag im Projektmappen-Explorer markieren, diesen nochmals anklicken und dann die Bezeichnung &auml;ndern. Danach erscheint noch eine Meldung, die fragt, ob Verweise auf das Codeelement angepasst werden sollen (siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_02\/pic_170_001.png\" alt=\"&Auml;ndern eines Klassennamens\" width=\"424,7115\" height=\"556,2415\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: &Auml;ndern eines Klassennamens<\/span><\/b><\/p>\n<p>Wenn Sie hier auf <b>Ja <\/b>klicken, werden in unserer kleinen Beispielanwendung folgende &Auml;nderungen durchgef&uuml;hrt:<\/p>\n<ul>\n<li>Die Bezeichnung der Klasse wird ebenfalls in <b>Foto <\/b>ge&auml;ndert.<\/li>\n<li>In der Klasse <b>FotoverwaltungContext <\/b>wird der Typ der Klasse des <b>DbSets <\/b>ebenfalls ge&auml;ndert:<\/li>\n<\/ul>\n<pre>Partial Public Class FotoverwaltungContext\r\n     Inherits DbContext\r\n     ...\r\n     <span style=\"color:blue;\">Public <\/span>Overridable Property tblFotos<span style=\"color:blue;\"> As <\/span>DbSet(Of Foto)\r\n     ...\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p>In dieser Klasse sind dann weitere &Auml;nderungen n&ouml;tig. Anschlie&szlig;end sieht die oben bereits teilweise ge&auml;nderte Zeile mit der Definition des <b>DbSet <\/b>wie folgt aus:<\/p>\n<pre><span style=\"color:blue;\">Public <\/span>Overridable Property Fotos<span style=\"color:blue;\"> As <\/span>DbSet(Of Foto)<\/pre>\n<h2>Mapping hinzuf&uuml;gen<\/h2>\n<p>Damit passen die Deklarationen der Klasse und des <b>DbSet<\/b>-Elements nun zu dem Code, den wir f&uuml;r die Konstruktor-Methode unseres Fensters <b>MainWindow.xaml <\/b>erstellt haben. Was geschieht nun, wenn wir die Anwendung starten<\/p>\n<p>Wir erhalten einen unerwarteten Fehler: Visual Studio bem&auml;ngelt, dass wir eine Eigenschaft namens <b>Foto <\/b>in der gleichnamigen Klasse verwenden (siehe Bild 2). Damit erhalten wir also noch ein Problem, das aus der Benennung der Tabellen und Felder der Beispieldatenbank resultiert. Das Feld <b>Foto <\/b>k&ouml;nnen wir nicht mit dem Eigenschaftsnamen <b>Foto <\/b>ansprechen, da eine Klasse keine Eigenschaften besitzen darf, die genauso hei&szlig;en wir die Klasse selbst. Also &auml;ndern wir den Namen der Eigenschaft in der Klasse <b>Foto <\/b>auf <b>Fotodaten<\/b>:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_02\/pic_170_002.png\" alt=\"Fehler beim Zugriff auf die Klasse\" width=\"649,559\" height=\"283,4141\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Fehler beim Zugriff auf die Klasse<\/span><\/b><\/p>\n<pre>Partial Public Class Foto\r\n     ...\r\n     <span style=\"color:blue;\">Public <\/span>Property Fotodaten<span style=\"color:blue;\"> As Byte<\/span>()\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p>Nach einem erneuten Start der Anwendung erhalten wir dann die Fehler, mit denen wir gerechnet h&auml;tten. Der erste lautet wie folgt und er tritt beim Zugriff auf die Daten &uuml;ber <b>dbContext.Fotos.First <\/b>auf (siehe auch Bild 3):<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_02\/pic_170_002.png\" alt=\"Fehler beim Zugriff auf die Tabelle\" width=\"649,559\" height=\"283,4141\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Fehler beim Zugriff auf die Tabelle<\/span><\/b><\/p>\n<pre>System.InvalidOperationException: \"Die Sequenz enth&auml;lt keine Elemente.\"<\/pre>\n<p>Das ist etwas &uuml;berraschend, denn wir hatten mit einem Fehler gerechnet, der durch eine fehlende Tabelle ausgel&ouml;st wird. Schauen wir uns die Eigenschaften der Auflistung <b>Fotos <\/b>wie in Bild 4 an, sehen wir, dass es Entity Framework anscheinend versucht, auf eine Tabelle namens <b>Fotoes <\/b>zuzugreifen. Das ist offensichtlich die Plural-Form der Klasse <b>Foto<\/b>, die Entity Framework automatisch gebildet hat, um auf die Tabelle zuzugreifen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_02\/pic_170_004.png\" alt=\"Der Zugriff erfolgt auf die nicht vorhandene Tabelle Fotoes\" width=\"700\" height=\"130,9316\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Der Zugriff erfolgt auf die nicht vorhandene Tabelle Fotoes<\/span><\/b><\/p>\n<p>Damit Entity Framework erkennt, dass wir &uuml;ber die <b>DbSet<\/b>-Auflistung Fotos auf die Daten der Tabelle <b>tblFotos <\/b>zugreifen wollen, f&uuml;gen wir der Methode <b>OnModelCreating <\/b>die folgende Anweisung hinzu:<\/p>\n<pre>Protected Overrides Sub OnModelCreating(ByVal modelBuilder<span style=\"color:blue;\"> As <\/span>DbModelBuilder)\r\n     modelBuilder.Entity(Of Foto)().ToTable(\"tblFotos\")\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Daraufhin erhalten wir die Meldung aus Bild 5, die uns darauf hinweis, dass das Unterst&uuml;tzungsmodell ge&auml;ndert worden sei und wir mit einer Code First-Migration die &Auml;nderungen im Datenmodell in die Datenbank &uuml;bertragen k&ouml;nnten. Was ist damit gemeint<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_02\/pic_170_006.png\" alt=\"Unterst&uuml;tzungsmodell ge&auml;ndert\" width=\"349,7625\" height=\"150,3979\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Unterst&uuml;tzungsmodell ge&auml;ndert<\/span><\/b><\/p>\n<p>Schauen wir uns nochmal den Inhalt des Objekts <b>Fotos <\/b>im Debug-Modus an, sehen wir, dass Entity Framework zwar nun auf die richtige Tabelle namens <b>tblFotos <\/b>zugreift (siehe Bild 6). Allerdings lautet der Name des Feldes nun <b>Fotodaten<\/b>. In der Tabelle <b>tblFotos <\/b>der Datenbank hei&szlig;t es allerdings <b>Foto<\/b>. Entity Framework denkt also nun offensichtlich anhand des Unterschiedes zwischen dem in der Abfrage genannten Feldnamen <b>Fotodaten <\/b>und dem in der Tabelle vorgefundenen Feld <b>Foto<\/b>, dass der Benutzer das Entity Data Modell ge&auml;ndert hat und bietet eine M&ouml;glichkeit an, diese &Auml;nderung in die Datenbank zu &uuml;bertragen. Das wollen wir allerdings nicht, sondern wir m&ouml;chten das Mapping so anpassen, dass f&uuml;r die Eigenschaft <b>Fotodaten <\/b>der Entit&auml;t <b>Foto <\/b>auf das Feld <b>Foto <\/b>der Tabelle <b>tblFotos <\/b>zugegriffen wird.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_02\/pic_170_007.png\" alt=\"Die Anwendung versucht zwar, auf die richtige Tabelle zuzugreifen (tblFotos), aber noch nicht auf das richtige Feld.\" width=\"700\" height=\"47,55981\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Die Anwendung versucht zwar, auf die richtige Tabelle zuzugreifen (tblFotos), aber noch nicht auf das richtige Feld.<\/span><\/b><\/p>\n<p>Also f&uuml;gen wir noch einen weiteren Teil zur Methode OnModelCreating hinzu, mit der wir das Feld Fotodaten auf das Feld Foto der Tabelle tblFotos mappen. Das sieht dann wie folgt aus:<\/p>\n<pre>Protected Overrides Sub OnModelCreating(ByVal modelBuilder<span style=\"color:blue;\"> As <\/span>DbModelBuilder)\r\n     modelBuilder.Entity(Of Foto)().\r\n         ToTable(\"tblFotos\").\r\n         Property(Function(t) t.Fotodaten).HasColumnName(\"Foto\")\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Beim n&auml;chsten Start erhalten wir allerdings wieder die gleiche Meldung mit dem Hinweis auf den Einsatz der Code First-Migrationen. Wenn wir uns den Inhalt von dbContect.Fotos ansehen, finden wir allerdings folgende SQL-Anweisung vor:<\/p>\n<pre>\"SELECT \" & <span style=\"color:blue;\">vbCrLf<\/span> & \"    [Extent1].[ID] AS [ID], \" & <span style=\"color:blue;\">vbCrLf<\/span> & \"    [Extent1].[Foto] AS [Foto]\" & <span style=\"color:blue;\">vbCrLf<\/span> & \"    FROM [dbo].[tblFotos] AS [Extent1]\"<\/pre>\n<p>Wenn wir diese SELECT-Anweisung im SQL Server Management Studio in einer neuen Abfrage f&uuml;r die hier verwendete Datenbank ausf&uuml;hren, erhalten wir allerdings das gew&uuml;nschte Ergebnis (siehe Bild 7). <\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_02\/pic_170_008.png\" alt=\"Die Abfrage funktioniert wie gew&uuml;nscht.\" width=\"424,7115\" height=\"293,6183\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Die Abfrage funktioniert wie gew&uuml;nscht.<\/span><\/b><\/p>\n<h2>Unterschiede per Migration aufdecken<\/h2>\n<p>In den Artikeln Datenbank-Initialisierung und Datenbank-Migration haben wir die Migration von Code First-Datenbanken in das jeweilige Datenbanksystem beschrieben. Wie dort erl&auml;utert, werden wir nun die Migration aktivieren. Wir wollen allerdings keine Migration ausf&uuml;hren, sondern diese nur nutzen, um herauszufinden, welche Unterschiede zwischen dem Entity Data Model und dem Datenmodell der Datenbank zu dem aufgetretenen Fehler f&uuml;hren. Also &ouml;ffnen Sie die Paket-Manager-Konsole und geben dort den folgenden Befehl ein:<\/p>\n<pre>enable-migrations<\/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\/55000170\/\">\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\/55000170?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\/55000170\/\"\/>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_login_nonce\" value=\"dbce743e9d\"\/>\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>Wenn Sie ein Entity Data Model mit der Vorlage &#8220;Code First aus Datenbank&#8221; auf Basis einer bestehenden Datenbank erstellen, haben Sie vielleicht Pech und die Namen der Tabellen der Datenbank und der enthaltenen Felder lauten nicht so, wie Sie die Entit&auml;tsklassen, die DbSet-Elemente und die Eigenschaften der Klassen nennen m&ouml;chten. Dann haben Sie verschiedene M&ouml;glichkeiten: Zum Beispiel k&ouml;nnen Sie die Bezeichnungen in der Datenbank anpassen. Das geht aber oft nicht, weil vielleicht noch andere Frontends auf die gleiche Datenbank zugreifen. Dann haben Sie noch die M&ouml;glichkeit, die Bezeichnungen von Datenbank und Entity Data Model so zu mappen, dass beide Seiten zufrieden sind. Wie letzteres gelingt, zeigen wir im vorliegenden Artikel am Beispiel der S&uuml;dsturm-Datenbank.<\/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":[66022019,662019,44000021,44000022],"tags":[],"yst_prominent_words":[],"class_list":["post-55000170","post","type-post","status-publish","format-standard","hentry","category-66022019","category-662019","category-Entity_Framework","category-Von_Access_zu_NET"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000170","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=55000170"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000170\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000170"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000170"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000170"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000170"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}