Site logo
Site logo
Programmieren aus Leidenschaft
Programmieren aus Leidenschaft

Object-Relational Mapping mit LINQ


LINQ ermöglich das von vielen Entwicklern erwartete Object-Relational Mapping, das direkte Verbinden von Datenbanken mit Programmobjekten wie Klassen oder Listen herstellt. Bisher war eine solche Funktionalität nur durch den Einsatz von Drittanbieter-Software möglich. In C# 3.0 ist es nun ein fester Bestandteil der Sprache.

Das Abbilden einer Datenbanktabelle auf eine Klasse ist ein sehr einfacher Vorgang. Nur die Mapping Informationen, die durch Attribute bestimmt werden, sind nötig um eine Verbindung zu definieren. Solche Klassen, die zum Mapping auf Datenbanktabellen benutzt werden, nennt man auch Entity-Klassen.
ormapping1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq.Mapping;

namespace myORMapping
{
   [Table (Name="tbl_personal")]
   class Cpersonal
   {
      [Column(Name = "ID", IsPrimaryKey = true)]
      public int id { get; set; }

      [Column (Name="FirstName")]
      public string firstName {get; set;}

      [Column (Name="LastName")]
      public string lastName {get; set;}

      [Column (Name="Age")]
      public int age {get; set;}
   }
}
Das Attribute einer Entity-Klasse bestimmt mit welcher Tabelle die Klasse verbunden wird und die Attribute der Eigenschaften bestimmen mit welchen Tabellenspalten sie verbunden werden.

Was noch fehlt ist ein DataContext, der bestimmt, in welcher Datenbank sich diese Tabelle befindet. Hier wird als Parameter ein ganz normaler Connection-String übergeben.
DataContext context = new DataContext("Data Source=.\\SQLEXPRESS;AttachDbFilename=|DataDirectory|\\database.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True");
Jetzt ist das Übertragen der Tabellendaten in ein Programm kein Problem mehr und kann dank LINQ mit einer einfachen Abfrage geschehen.
var personalliste = from c in context.GetTable() select c;

foreach (var person in personalliste)
{
   MessageBox.Show(person.firstName);
}
Natürlich kann man das Ergebnis der Abfrage auch direkt auf eine generische Liste abbilden.
List personalliste = new List(from c in context.GetTable() select c );
Und auch innerhalb der Schleife kann man statt impliziter Typisierung die Cpersonal-Klasse verwenden was wahrscheinlich die Lesbarkeit des Codes etwas verbessert.
foreach (Cpersonal person in personalliste)
{
   MessageBox.Show(person.firstName);
}
Auch das Hinzufügen neuer Daten an die Tabelle ist nicht weiter kompliziert. Ein neues Objekt ist schnell erstellt und wird mit InsertOnSubmit an die Tabelle angehängt.
Cpersonal pers = new Cpersonal();
pers.firstName = "Gabi";
pers.lastName = "Gold";
pers.age = 29;
pers.id = 74742632;

context.GetTable().InsertOnSubmit(pers);
context.SubmitChanges();
Um auch die generische Liste zu aktualisieren muss man entweder die Tabelle neu einlesen oder das neu erzeugte Objekt auch an diese Liste anhängen.
personalliste.Add(pers);
Auch das Ändern/Bearbeiten von Daten ist sehr einfach. Die Objekteigenschaften werden überschrieben und das Objekt wird in der Tabelle aktualisiert.
personalliste[position].firstName = "Sascha";
personalliste[position].lastName = "Silber";
personalliste[position].age = "16";
context.SubmitChanges();
Auch Änderungen an mehreren Datensätzen sind leicht möglich. Es kann jederzeit eine neue Abfrage im selben Context gemacht werden. Die Änderungen werden dann sofort in der generischen Liste und in der Datenbank aktualisiert.
var persList = from pers in context.GetTable() where pers.age > 99 select pers;

foreach (Cpersonal p in persList)
{
   p.age = 99;
}

context.SubmitChanges();
Will man hingegen Datensätze löschen geht dies mit der DeleteOnSubmit-Methode. Der Aufruf ist wieder denkbar einfach:
context.GetTable().DeleteOnSubmit(personalliste[position]);
context.SubmitChanges();
Dieser Aufruf löscht nur die Einträge in der Datenbank, Objekte aus der generischen Liste müssen wieder seperat entfernt werden.