{"id":55000252,"date":"2021-02-01T00:00:00","date_gmt":"2021-04-29T18:36:52","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=252"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Code_First_Mapping_per_Fluent_API","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/Code_First_Mapping_per_Fluent_API\/","title":{"rendered":"Code First Mapping per Fluent API"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg02.met.vgwort.de\/na\/be819711007c46f88955169e48185060\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Wenn Sie ein Code First-Entity Data Model entwerfen, gibt es bestimmte Konventionen, die standardm&auml;&szlig;ig greifen. So hei&szlig;en Entit&auml;ten wie der Singular der zugrunde liegenden Tabellennamen oder der Prim&auml;r- und Fremdschl&uuml;ssel werden aus Feldern abgeleitet, welche die Zeichenkette ID enthalten &#8211; gegebenenfalls kombiniert mit dem Entit&auml;tsnamen. Wenn Sie mit einem Datenmodell daherkommen, dessen Tabellen das Pr&auml;fix &#8220;tbl&#8221; mitbringen, wollen Sie dieses nicht in den Entit&auml;tsnamen wiederfinden und gegebenenfalls m&ouml;chten (oder m&uuml;ssen) Sie auch noch Feldnamen &auml;ndern und diese anschlie&szlig;end mappen. Eine M&ouml;glichkeit dazu finden Sie in den Methoden der Fluent Api, die wir in diesem Artikel beschreiben.<\/b><\/p>\n<h2>Warum Mapping zwischen Datenmodell und Entit&auml;ten<\/h2>\n<p>Wenn Sie ein Entity Data Model auf Basis des Datenmodells einer Datenbank erstellen oder andersherum, ist immer eine bestimmte Art von Mapping erforderlich. Im Optimalfall sind die Tabellen- und Feldnamen genau so eingestellt, dass diese den DbSet- und Entit&auml;tsnamen entsprechen. <\/p>\n<p>Sobald Sie aber ein Datenmodell erhalten, das beispielsweise Tabellennamen mit dem Pr&auml;fix <b>tbl <\/b>(wie <b>tblArtikel<\/b>) enth&auml;lt und wo die Feldnamen vielleicht nicht den W&uuml;nschen des Entwicklers f&uuml;r die Eigenschaften der Entit&auml;ten entsprechen, m&uuml;ssen Sie diese auf irgendeine Weise anpassen. Das Datenmodell anzupassen w&auml;re toll, aber in manchen F&auml;llen greifen noch andere Anwendungen auf die Datenbank zu, sodass Sie die Namen von Tabellen und Feldern nicht einfach &auml;ndern k&ouml;nnen.<\/p>\n<p>Also stellt das Entity Framework M&ouml;glichkeiten bereit, das Mapping zwischen den Tabellen und Feldern auf der einen und den DbSets und Eigenschaften auf der anderen Seite anzupassen.<\/p>\n<p>Dabei kann das Mapping f&uuml;r verschiedene Zwecke genutzt werden:<\/p>\n<ul>\n<li>Wenn Sie ein Entity Data Model auf Basis einer bestehenden Datenbank etwa vom SQL Server f&uuml;r Code First erstellt haben und die Auflistungen, Entit&auml;tsklassen und ihre Eigenschaften so anpassen wollen, dass es Ihren Programmierkonventionen entspricht, auch wenn die Definition der Tabellen und Felder anders lautet oder<\/li>\n<li>wenn Sie ein Entity Data Model als Code First-Model programmiert haben und dann per Migration-Funktionalit&auml;t daraus die Datenbank erzeugen wollen. Wie dies gelingt, schauen wir uns an einigen Beispielen in den folgenden Abschnitten im Detail an.<\/li>\n<\/ul>\n<h2>Mapping mit der Fluent API<\/h2>\n<p>Die Fluent API des Entity Frameworks bietet Methoden, die genau an einer Stelle innerhalb des Entity Data Models ausgef&uuml;hrt werden: in der &Uuml;berschreibung der Methode <b>OnModelCreating <\/b>der <b>DbContext<\/b>-Klasse. Entity Framework ruft diese Methode beim Erstellen des Entity Data Models auf und f&uuml;hrt die dort angegebenen Anweisungen zum Anpassen des Mappings aus.<\/p>\n<h2>Beispielprojekt<\/h2>\n<p>Das Beispielprojekt erstellen wir als neues Projekt des Typs <b>WPF-App (.NET Framework) <\/b>f&uuml;r Visual Basic. Damit wir die nun zu erstellenden Elemente in eine Datenbank &uuml;bertragen k&ouml;nnen, f&uuml;gen wir dem Projekt ein neues Element des Typs <b>ADO.NET Entity Data Model <\/b>hinzu und nennen dieses <b>FluidAPIContext<\/b> (siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_252_002.png\" alt=\"Entity Data Model hinzuf&uuml;gen\" width=\"599,593\" height=\"374,7455\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Entity Data Model hinzuf&uuml;gen<\/span><\/b><\/p>\n<p>Dabei verwenden wir als Vorlage <b>Leeres Code First-Modell <\/b>(siehe Bild 2). Nach einem Klick auf die Schaltfl&auml;che <b>Fertigstellen<\/b> erhalten wir im Projektmappen-Explorer ein neues Element namens <b>FluidAPIContext.vb <\/b>sowie ein paar neue Eintr&auml;ge in der Datei <b>App.config <\/b>&#8211; zum Beispiel die Verbindungszeichenfolge zum Erstellen beziehungsweise f&uuml;r den Zugriff auf die Datenbank f&uuml;r diese L&ouml;sung.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_252_001.png\" alt=\"Neues Entity Data Model als leeres Code First-Modell\" width=\"599,593\" height=\"353,7306\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Neues Entity Data Model als leeres Code First-Modell<\/span><\/b><\/p>\n<h2>Einfache Tabelle erstellen<\/h2>\n<p>Zu einer einfachen Tabelle geh&ouml;rt ein eindeutiges Prim&auml;rschl&uuml;sselfeld mit Autowert-Funktion sowie die ben&ouml;tigten Felder. Wir beginnen mit einer Entit&auml;t, auf deren Basis eine Tabelle namens <b>Anreden <\/b>entstehen soll. Diese soll die Felder <b>ID <\/b>und <b>Name <\/b>enthalten. Dazu legen wir eine neue Klassendatei namens <b>Anrede.vb <\/b>an. Der Code der Klasse lautet vorerst:<\/p>\n<pre><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 Name<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p>F&uuml;r dieses Element f&uuml;gen wir der <b>DbContext<\/b>-Klasse eine Auflistung hinzu:<\/p>\n<pre><span style=\"color:blue;\">Public Class<\/span> FluidAPIContext\r\n     Inherits DbContext\r\n     <span style=\"color:blue;\">Public <\/span>Sub New()\r\n         MyBase.New(\"name=FluidAPIContext\")\r\n     End Sub\r\n     <span style=\"color:blue;\">Public <\/span>Overridable Property Anreden<span style=\"color:blue;\"> As <\/span>DbSet(Of Anrede)\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p>Um daraus die Datenbank mit der ersten Tabelle zu erstellen, ben&ouml;tigen wir die Paket-Manager-Konsole, die wir mit dem Befehl <b>Extras|NuGet-Paketmanager|Paket-Manager-Konsole <\/b>anzeigen. In der Konsole setzen Sie nacheinander die folgenden Anweisungen ab:<\/p>\n<ul>\n<li><b>Enable-Migrations<\/b>: Aktiviert die Migrationen vom Entity Data Model zu einer SQL Server-Datenbank. Dies f&uuml;gt den Ordner <b>Migrations <\/b>mit der Datei <b>Configuration.vb <\/b>zum Projekt im Projektmappen-Explorer hinzu.<\/li>\n<li><b>Add-Migration Init<\/b>: Erstellt die Befehle f&uuml;r die initiale Migration, die beispielsweise in einer Datei namens <b>202103111053588_Init.vb <\/b>im Ordner <b>Migrations <\/b>angelegt wird. Die hier gespeicherten Befehle werden f&uuml;r das Erstellen beziehungsweise Anpassen der Datenbank verwendet.<\/li>\n<li><b>Update-Database<\/b>: F&uuml;hrt die in der mit <b>Add-Migration <\/b>erstellten Klasse enthaltenen Befehle aus, um die Datenbank erstmalig zu erstellen und die angegebene Tabelle anzulegen.<\/li>\n<\/ul>\n<p>Dies erstellt die neue Datenbank und eine Tabelle, die wir uns im SQL Server Management Studio anschauen k&ouml;nnen (den Zielserver und den Namen der Datenbank k&ouml;nnen Sie der Verbindungszeichenfolge in der Datei <b>App.config <\/b>entnehmen). Das Ergebnis sieht wie in Bild 3 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2021_01\/pic_252_003.png\" alt=\"Die neue Tabelle in der frisch erzeugten Datenbank\" width=\"649,559\" height=\"408,3434\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Die neue Tabelle in der frisch erzeugten Datenbank<\/span><\/b><\/p>\n<h2>Eingesetzte Konventionen<\/h2>\n<p>Hier erkennen wir gleich, dass bei der Erstellung der Tabelle einige Konventionen umgesetzt wurden. So hat Entity Framework automatisch erkannt, dass die Eigenschaft <b>ID <\/b>wohl als Prim&auml;rschl&uuml;sselfeld mit Autowertfunktion verwendet werden soll. Au&szlig;erdem hat es das Feld <b>Name <\/b>als Feld mit dem Datentyp <b>nvarchar(MAX) <\/b>angelegt, der Nullwerte erlaubt. Als Tabellenname hat Entity Framework aus der Entit&auml;tsklasse namens <b>Anrede <\/b>den Namen <b>Anredes <\/b>erzeugt.<\/p>\n<p>Dies resultiert ebenfalls aus einer Konvention, die daf&uuml;r sorgt, dass Entity Framework den Tabellenamen aus dem Namen der Entit&auml;tsklasse plus dem <b>s <\/b>f&uuml;r den englischen Plural zusammenstellt.<\/p>\n<h2>Umgehen der Konventionen<\/h2>\n<p>In den folgenden Abschnitten schauen wir uns an, wie wir diese Konventionen durch Verwendung von Elementen der FluentAPI f&uuml;r das Entity Framework umgehen und mit eigenen Konventionen ersetzen k&ouml;nnen. Wir wollen zun&auml;chst die folgenden Dinge &auml;ndern:<\/p>\n<ul>\n<li>Der Tabellenname soll <b>Anreden <\/b>lauten oder gegebenenfalls auch <b>tblAnreden<\/b>.<\/li>\n<li>Der Felddatentyp des Feldes <b>Name <\/b>soll <b>nvarchar(50) <\/b>lauten.<\/li>\n<li>Das Prim&auml;rschl&uuml;sselfeld soll den Namen <b>AnredeID <\/b>erhalten.<\/li>\n<li>Das Feld <b>Name <\/b>soll in der Tabelle den Namen <b>Anrede <\/b>erhalten.<\/li>\n<\/ul>\n<h2>Anpassen des Tabellennamens<\/h2>\n<p>Als Erstes setzen wir die Konvention au&szlig;er Kraft, die daf&uuml;r sorgt, dass die zu erstellende Tabelle den Namen der Entit&auml;tsklasse plus dem Plural-s als Bezeichnung erh&auml;lt. Dazu f&uuml;gen wir der Klasse <b>FluentApiContext <\/b>die Methode <b>OnModelCreating <\/b>hinzu und legen dort eine Anweisung an, welche die Konvention aufhebt:<\/p>\n<pre><span style=\"color:blue;\">Public Class<\/span> FluidAPIContext\r\n     Inherits DbContext\r\n     ...\r\n     <span style=\"color:blue;\">Public <\/span>Overridable Property Anreden<span style=\"color:blue;\"> As <\/span>DbSet(Of Anrede)\r\n     Protected Overrides Sub OnModelCreating(ByVal modelBuilder<span style=\"color:blue;\"> As <\/span>DbModelBuilder)\r\n         modelBuilder.Conventions.Remove(Of PluralizingTableNameConvention)()\r\n     End Sub\r\n<span style=\"color:blue;\">End Class<\/span><\/pre>\n<p>Um den Typ <b>PluralizingTableNameConvention <\/b>zu nutzen, f&uuml;gen wir einen weiteren Namespace zu der Klassendatei hinzu:<\/p>\n<pre>Imports System.Data.Entity.ModelConfiguration.Conventions<\/pre>\n<p>Nun aktualisieren wir das Datenmodell, indem wir die folgenden beiden Anweisungen in der Paket-Manager-Konsole aufrufen:<\/p>\n<pre>Add-Migration Init\r\nUpdate-Database<\/pre>\n<p>Danach finden wir die Tabelle in der Datenbank unter dem Namen <b>Anrede <\/b>vor. Wir m&ouml;chten allerdings den Namen <b>Anreden <\/b>oder auch <b>tblAnreden<\/b>. Dazu f&uuml;gen wir der Methode <b>OnModelCreating <\/b>eine weitere Anweisung hinzu:<\/p>\n<pre>modelBuilder.Entity(Of Anrede)().ToTable(\"Anreden\")<\/pre>\n<p>Wenn Sie den Namen <b>tblAnreden <\/b>verwenden m&ouml;chten, nutzen Sie einfach folgende Anweisung:<\/p>\n<pre>modelBuilder.Entity(Of Anrede)().ToTable(\"tblAnreden\")<\/pre>\n<p>Um diese &Auml;nderungen durchzuf&uuml;hren, rufen Sie immer wieder die beiden Anweisungen in der Paket-Manager-Konsole auf &#8211; wir weisen in den folgenden Abschnitten nicht mehr explizit darauf hin. Au&szlig;erdem m&uuml;ssen Sie, um die &Auml;nderungen in der SQL Server Management Konsole zu sehen, das Element <b>Tables <\/b>&uuml;ber den Kontextmen&uuml;-Eintrag <b>Refresh <\/b>aktualisieren.<\/p>\n<h2>Anpassen des String-Felddatentyps<\/h2>\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\/55000252\/\">\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\/55000252?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\/55000252\/\"\/>\n\t\t\t\t<input type=\"hidden\" name=\"rcp_login_nonce\" value=\"9fac6dd15a\"\/>\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 Code First-Entity Data Model entwerfen, gibt es bestimmte Konventionen, die standardm&auml;&szlig;ig greifen. So hei&szlig;en Entit&auml;ten wie der Singular der zugrunde liegenden Tabellennamen oder der Prim&auml;r- und Fremdschl&uuml;ssel werden aus Feldern abgeleitet, welche die Zeichenkette ID enthalten &#8211; gegebenenfalls kombiniert mit dem Entit&auml;tsnamen. Wenn Sie mit einem Datenmodell daherkommen, dessen Tabellen das Pr&auml;fix &#8220;tbl&#8221; mitbringen, wollen Sie dieses nicht in den Entit&auml;tsnamen wiederfinden und gegebenenfalls m&ouml;chten (oder m&uuml;ssen) Sie auch noch Feldnamen &auml;ndern und diese anschlie&szlig;end mappen. Eine M&ouml;glichkeit dazu finden Sie in den Methoden der Fluent Api, die wir in diesem Artikel beschreiben.<\/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":[66012021,662021,44000021],"tags":[],"yst_prominent_words":[],"class_list":["post-55000252","post","type-post","status-publish","format-standard","hentry","category-66012021","category-662021","category-Entity_Framework"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000252","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=55000252"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000252\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000252"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000252"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000252"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000252"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}