Tipp-Upload: VB.NET 0303: LinqToSQL-DataContext
von Spatzenkanonier
Über den Tipp
Dieser Tippvorschlag ist noch unbewertet.
Der Vorschlag ist in den folgenden Kategorien zu finden:
- Datenbanken und XML
Dem Tippvorschlag wurden folgende Schlüsselwörter zugeordnet:
LinqToSQL, DataContext, Dataset
Der Vorschlag wurde erstellt am: 21.08.2008 02:03.
Die letzte Aktualisierung erfolgte am 11.01.2009 12:34.
Beschreibung
Die LinqToSQL - Klasse (DataContext, Dbml) ist der Nachfolger des bisherigen typisierten Datasets. Es beinhaltet einen OR-Mapper, bei dem man die Datenklassen in einem besseren Designer als dem Dataset-Designer designen kann.
Der generierte Code der Datenklassen ist wesentlich eleganter, vermutlich auch performanter, v.a. aber leserlicher als die bisherigen, in die "XYDataset.Designer.vb" generierten Klassen.
Ein "lazy loading" (Nachladen von Daten erst, wenn sie gebraucht werden) ist voreingestellt.
Die Umständlichkeit, mit mehreren TableAdaptern zu hantieren, entfällt - der Datacontext wird als Einheit abgespeichert.
Interessant die Option, sich die generierten SQL-Commands ausgeben zu lassen.
Besonders angenehm (und das wesentliche an diesem Tipp):
Mit dem Befehl .CreateDatabase() kann ein Datacontext eine SQLServer-Datenbank neu generieren, passend zu den im Dbml-Designer erstellten Datenklassen. Die Arbeit im total unübersichtlichen "Tabellen-Designer" des Datenbank-Explorers kann also durch den komfortablen Dbml-Designer ersetzt werden.
3 (sehr wehe) Wehmutstropfen:
- Der DataContext unterstützt ausschließlich den SQL-Server. Das Dataset bestand unabhängig von jeder Datenbank. Für "kleine" Einheiten (bis 5MB) konnte man u.U. performanter jeweils komplett von der Festplatte laden/speichern, anstatt einen Datenbank-Provider zu bemühen. Diese Option fällt derzeit weg.
- Im Dbml-Designer gibt es keine Möglichkeit, bei der zu generierenden Datenbank eine Löschweitergabe für verknüpfte Tabellen zu designen. Man muß im generierten Code alle vorgefundenen Association-Attribute mit dem zusätzlichen optionalen Paramater DeleteRule:="Cascade" nachbessern. Diese Nachbesserung muß nach jedem Neu-Generieren der Dbml erneut erfolgen.
- Der OR-Mapper generiert für Löschungen untergeordneter Datensätze kein DELETE-Command, sondern ein UPDATE, das den Foreign-Key auf DBNull setzt. Dieses Verhalten kann die hier vorgestellte Klasse "DataContextBase" korrigieren, die im Dbml-Designer als Base-Class anzugeben ist.
Schwierigkeitsgrad |
Verwendete API-Aufrufe: |
Download: |
' Dieser Source stammt von http://www.activevb.de ' und kann frei verwendet werden. Für eventuelle Schäden ' wird nicht gehaftet. ' Um Fehler oder Fragen zu klären, nutzen Sie bitte unser Forum. ' Ansonsten viel Spaß und Erfolg mit diesem Source! ' ' Beachten Sie, das vom Designer generierter Code hier ausgeblendet wird. ' In den Zip-Dateien ist er jedoch zu finden. ' ------------ Anfang Projektgruppe CreateMdf.sln ------------ ' ----------- Anfang Projektdatei CreateMdf.vbproj ----------- ' ------------- Anfang Datei DataContextBase.vb ------------- ' IDE-Voreinstellungen: ' Option Strict On ' Option Explicit On ' Option Infer On ' Projekt-Voreinstellungen ' Imports System ' Imports System.Drawing ' Imports System.Windows.Forms ' Imports System.Collections.Generic ' Imports System.Linq Imports System.Reflection Imports System.Data.Linq Imports System.Data.Linq.Mapping Public MustInherit Class DataContextBase Inherits DataContext Protected Sub New(ByVal connection As System.Data.IDbConnection, ByVal mappingSource As _ MappingSource) ' diese eigentlich nutzlose New-Überladung ist erforderlich, da der Dbml-Designer ' Code generiert, der darauf zugreift MyBase.New(connection) Throw New NotSupportedException End Sub Protected Sub New(ByVal connection As String, ByVal mappingSource As MappingSource) MyBase.New(connection, mappingSource) End Sub Public Overrides Sub SubmitChanges(ByVal failureMode As ConflictMode) For Each Entity In MyBase.GetChangeSet.Updates ' Ist bei einer Entity ein ForeignKey auf Null gesetzt, so ist diese Entity zu ' löschen statt zu updaten Dim tpU = Entity.GetType Dim Tb = MyBase.GetTable(tpU) Dim E = Entity Dim F = From Association In MyBase.Mapping.GetMetaType(tpU).Associations Where _ Association.IsForeignKey AndAlso DirectCast(Association.ThisMember.Member, _ PropertyInfo).GetValue(E, Nothing) Is Nothing If F.Any() Then Tb.DeleteOnSubmit(E) Exit For End If Next MyBase.SubmitChanges(failureMode) End Sub End Class ' -------------- Ende Datei DataContextBase.vb -------------- ' --------------- Anfang Datei frmCreateMdf.vb --------------- Imports System.IO Imports System.Reflection Public Class frmCreateMdf ' zum Databinding: im Datenfenster wurde diesem Projekt eine Objekt-DataSource ' hinzugefügt, erzeugt aus der Klasse CreateMdf.Category (dem übergeordneten Datenobjekt ' des Dbml-Designers) ' das Category-Item wurde aus dem Datenfenster auf das linke DataGridView gezogen, das ' im Category-Item enthaltene Articles-Item auf das rechte Grid. Private _DBName As String = Path.GetFullPath("DataBase.mdf") Private _DB As MdfTemplateDataContext Private Sub frmCreateMdf_Load(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles Me.Load ReConnectDB() End Sub Private Sub ReConnectDB() ' Verwerfen und neu erstellen des DataContextes stellt den Zustand vor dem letzten ' .SubmitChanges() wieder her. If _DB IsNot Nothing Then _DB.Dispose() _DB = New MdfTemplateDataContext(_DBName) _DB.Log = Console.Out Me.CategoryBindingSource.DataSource = _DB.Categories End Sub Private Sub RecreateDB() If _DB.DatabaseExists Then ' _DB.CreateDatabase() bewirkt auch einen Eintrag bei der SQL-Server-Instanz des ' Computers. Daher muß vor Neu-Erstellung einer schon vorhandenen .mdf die ' vorherige Version mit DeleteDatabase() entfernt und ausgetragen werden. _DB.DeleteDatabase() End If _DB.Dispose() _DB = New MdfTemplateDataContext(_DBName) _DB.Log = Console.Out _DB.CreateDatabase() Me.CategoryBindingSource.DataSource = _DB.Categories End Sub Private Sub MenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles ReCreateToolStripMenuItem.Click, ReConnectToolStripMenuItem.Click, _ SaveToolStripMenuItem.Click, GenerateEntriesToolStripMenuItem.Click Select Case True Case sender Is ReCreateToolStripMenuItem RecreateDB() Case sender Is ReConnectToolStripMenuItem ReConnectDB() Case sender Is GenerateEntriesToolStripMenuItem Dim Rnd As New Random(Environment.TickCount) Static ID As Integer For I = 0 To 1 ID += 1 Dim Cat As New Category() With {.Name = "Category" & ID} For J = 0 To 2 ID += 1 Dim ArtName = Cat.Name & "Article" & ID Dim Art = New Article() With {.Name = ArtName, .Price = Rnd.Next(0, _ 10000) / 100} Cat.Articles.Add(Art) Next CategoryBindingSource.List.Add(Cat) Next Case sender Is SaveToolStripMenuItem _DB.SubmitChanges() End Select End Sub Private Sub frmCreateMdf_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles Me.Disposed _DB.Dispose() End Sub End Class ' ---------------- Ende Datei frmCreateMdf.vb ---------------- ' ------------ Ende Projektdatei CreateMdf.vbproj ------------ ' ------------- Ende Projektgruppe CreateMdf.sln -------------
Diskussion
Diese Funktion ermöglicht es, Fragen, die die Veröffentlichung des Tipps betreffen, zu klären, oder Anregungen und Verbesserungsvorschläge einzubringen. Nach der Veröffentlichung des Tipps werden diese Beiträge nicht weiter verlinkt. Allgemeine Fragen zum Inhalt sollten daher hier nicht geklärt werden.
Um eine Diskussion eröffnen zu können, müssen sie angemeldet sein.