HowTo: RSS Feeds mit C# / XLINQ lesen

imageVor einige Zeit hatte ich schon etwas zu XLinq (oder Linq to Xml) geschrieben. RSS Feeds einlesen ist eigentlich keine große Sache, weil der Standard recht simpel ist. Allerdings gibt es da auch Abweichungen ;)
Da ich bereits geschrieben habe wie man ein RSS Feed erstellt, zeige ich nun an einem einfachen Beispielen wie man RSS Feeds einlesen kann.

Weiterlesen »

HowTo: PicLens und andere MediaRSS Clients für die eigene Webseite nutzen (MediaRSS mit LINQ to XML erstellen)

Dieses HowTo ist im Zusammenhang mit dem normalen “RSS XLINQ” Post entstanden – ist allerdings wesentlich cooler.

Worum geht es?
Es geht um den “MediaRSS” Standard und wie man diesen für sich nutzen kann. Noch nie davon gehört? Ich bis heute auch nicht.
Allerdings gibt es ein bekanntes Firefox Plugin welches mit darauf basiert – die Rede ist von “PicLens“.

image 

Was kann “PicLens”?
“PicLens” bietet eine sehr schicke Oberfläche für verschiedene bekannte Dienste wie YouTube, Google Bildersuche, Flickr oder auch Amazon:

image
Hier mal die Amazon-Ansicht:

image

Media RSS
PicLens kann auch mit dem oben genannten “MediaRSS” Standard umgehen – auf der Seite ist auch gut beschrieben wie man das macht. Da wir bereits ein RSS Feed mit XLinq erstellt haben, dürfte das ja nicht sonderlich schwerer sein.

XLINQ

Wir haben den selben Projektaufbau – nur in der ASHX müssen wir die Erstellung etwas anpassen:

        XNamespace media = "http://search.yahoo.com/mrss";
        XNamespace atom = "http://www.w3.org/2005/Atom";
        public void ProcessRequest(HttpContext context)
        {

            XDocument document = new XDocument(
                                    new XDeclaration("1.0", "utf-8", "yes"),
                                    new XElement("rss",
                                        new XAttribute("version", "2.0"),
                                        new XAttribute(XNamespace.Xmlns + "media", media),
                                        new XAttribute(XNamespace.Xmlns + "atom", atom),
                                        new XElement("channel", this.CreateElements())
                                       ));

            context.Response.ContentType = "text/xml";
            document.Save(context.Response.Output);
            context.Response.End();
        }

        private IEnumerable<XElement> CreateElements()
        {
            List<XElement> list = new List<XElement>();

            for(int i = 1; i < 100; i++)
            {
                XElement itemElement = new XElement("item",
                                            new XElement("title", i),
                                            new XElement("link", "Code-Inside.de"),
                                            new XElement(media + "thumbnail",
                                                new XAttribute("url", "http://code-inside.de/blog/wp-content/uploads/image-thumb" + i + ".png")),
                                            new XElement(media + "content",
                                                new XAttribute("url", "http://code-inside.de/blog/wp-content/uploads/image-thumb" + i + ".png"))
                                       );
                list.Add(itemElement);
            }

            return list;
        }

In dem ASHX Handler haben wir nun noch zwei zusätzliche XNamespaces deklariert. Diese sind (laut der Piclens Seite) notwendig um erstmal dieses XML zu erzeugen:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss" xmlns:atom="http://www.w3.org/2005/Atom">
...
</rss>

Diese Namespaces werden über ein XAttribute hinzugefügt. Der Syntax ist meiner Meinung nach etwas ungünstig – ein “new XNamespace” oder etwas ähnliches hatte nicht funktioniert. Auch ein “new XElement(’xmlns:media’,'…’)” wurde mit einer Exception belohnt – daher dieser Weg.

In der CreateElement Methode müssen wir nur noch die “media:thumbnail” + “media:content” erstellen und fertig sind wir. Zusätzlich könnte man noch die anderen Elemente des Standards einbauen – schaut einfach nochmal in den Guide.

Ergebnis:
Da wir in unserem Head immer noch den Link zum RSS Feed angegeben haben, prüft PicLens automatisch ob man die Bilder auf der “Wall” anzeigen kann:

image

image 
Wer also viele Bilder auf seiner Webseite hat, könnte dies doch leicht umsetzen – insbesondere da dies ein offener Standard (Specification @ Yahoo) ist und ich davon ausgehe, dass sowas noch häufiger eingesetzt wird. Ob nun PicLens als Client ist ja am Ende auch egal :)

[ Download Source Code ]

PS: Als Bildquelle hab ich mal den Blog genommen – bitte aus Trafficgründen nicht überstrapazieren ;)

HowTo: RSS Feeds mit LINQ to XML erstellen (XLinq)

Ein XML zu erstellen ist mit Linq to XML recht einfach – ähnliches habe ich bereits in diesem HowTo beschrieben.

Der Unterschied ist eigentlich nur in der Verwendung und in dem dynamischen anlegen der Items zu finden.

Hier erstmal der Projektaufbau:

image

Damit unsere Besucher auch auf den RSS Feed aufmerksam werden, hab ich noch im HEAD einen Link auf den RSS-Feed gemacht:

<head runat="server">
    <title>Untitled Page</title>
    <link rel="alternate" href="Rss.ashx" type="application/rss+xml" title="" id="rss" />
</head>

Die “Rss.ashx”:

Das Grundgerüst erzeugen wir direkt in der ProcessRequest Methode:

        public void ProcessRequest(HttpContext context)
        {

            XDocument document = new XDocument(
                                    new XDeclaration("1.0", "utf-8", "yes"),
                                    new XElement("rss",
                                        new XAttribute("version", "2.0"),
                                        new XElement("channel", this.CreateElements())
                                       ));

            context.Response.ContentType = "text/xml";
            document.Save(context.Response.Output);
            context.Response.End();
        }

Hier wird die Deklaration gemacht und das XDocument wird in den Response.Output geschrieben. Unsere Items erzeugen wir an einer anderen Stelle – und zwar in der “CreateElements” Methode.

Die “CreateElements“-Methode:

Diese Methode gibt IEnumberable<XElement> zurück und kann somit direkt in den Baum eingefügt werden:

private IEnumerable<XElement> CreateElements()
        {
            List<XElement> list = new List<XElement>();

            for (int i = 1; i < 100; i++)
            {
                XElement itemElement = new XElement("item",
                                            new XElement("title", i),
                                            new XElement("link", "http://code-inside.de")
                                       );
                list.Add(itemElement);
            }

            return list;
        }

Sehr einfach und schnell gemacht :)

[ Download Source Code ]

HowTo: LINQ to SQL debuggen

Da ich in einem aktuellen Projekt LINQ to SQL einsetze, kam irgendwann der Punkt: Wie debuggt man das ordentlich? Wie sieht das SQL aus, was der zum Server schickt?

1. Variante: Visual Studio

Die einfachste (und nahliegendste) Variante: Das debuggen mit Visual Studio

Einfach schauen, wie die Objekte gefüllt werden und schauen ob das überhaupt logisch passt.

Für ein Großteil der Fehler reicht dies erstmal, allerdings fragt man sich doch machmal, was LINQ to SQL eigentlich für einen SQL Statement produziert.

2. Variante: LINQ to SQL Debug Visualizer

Dafür gibts den LINQ to SQL Debug Visualizer. Es ist mir unbegreiflich, warum Microsoft so ein geniales Tool so versteckt.

3. Variante: DataContext.Log

Wer nicht immer den Debug Visualizer nutzen kann oder mag, hat Microsoft etwas in LINQ to SQL eingebaut: DataContext.Log 

In Konsolenanwendungen ist dies auch praktisch – allerdings ist dies in Klassenbibliotheken ist dies nicht so einfach möglich. Allerdings gibts hier eine kleine Klasse, welche ermöglicht, dass das generierte SQL in dem Debug Output Fenster sichtbar ist: Sending the LINQ To SQL log to the debugger output window

Ich werde sicherlich noch den einen oder anderen Post zum Thema LINQ to SQL schreiben – allerdings sind manche Probleme auch zum Teil vom Konzept so oder leicht "trickreich" ;)

Diese 3. Varianten machen aber das Leben schon etwas leichter.

HowTo: LINQ to XML – Daten schreiben

Zuletzt haben wir bereits über LINQ to XML Daten gelesen, nun wollen wir Daten einfach mal schreiben.

Wie bereits in dem anderen HowTo geschrieben, versteckt sich die gesamte Funktionalität eigentlich im System.Xml.Linq Namespace. In der "prä-.NET 3.5" Zeit hat man über einen XmlWriter oder über XmlDocument mühselig die ganze Struktur aufbauen müssen und (jedenfalls bei XmlDocument) über Append anhängen.

Herzstück der gesamten Demoanwendung ist eigentlich das XElement (für die eigentlichen Xml Elemente) & XAttribut (für Xml Attribute).

Schauen wir uns erstmal das Ergebnis an:

image

Und hier der Code dafür (ich bin immer noch ohne Live Writer Plugin unterwegs, download siehe unten):

image

Dieses Konstrukt sieht vielleicht auf dem ersten Blick seltsam aus, allerdings ist es durch die Formatierung klar und deutlich gegliedert. Max. die Kommas & Klammern muss man beachten.

Der Grund für diese schicke Lösung, liegt in den Konstruktor der XElement Klasse – welche beliebig viele Nodes aufnehmen kann. Das kann man natürlich beliebig fortsetzen.

Das war es schon – jetzt kann man dieses XElement in ein XDocument einbetten und speichern – oder den String speichern etc.

Weitere Infos befinden sich z.B. hier (oder in meinem anderen Blogeintrag).

[ Download Source Code ]

HowTo: SQL Server Compact Edition mit LINQ to SQL verwenden

Auf der VSone habe ich das erste mal von den SQL Server in der Compact Edition (Version 3.5 ist momentan aktuell) gehört. In dem dazugehörigen Blogeintrag habe ich bereits einige der wichtigsten Angaben zu dem SQL Server Compact Edition geschrieben.

Kurzzusammenfassung:

- SQL DB für bis zu 4 GB Daten
- Bekannte Tools nutzbar
- Benötigt keine Installation etc.
- Relationen sind einstellbar

Kleines Problem: Geht LINQ to SQL?

Wer einmal mit LINQ to SQL gearbeitet hat, wird es sicherlich schick finden – jedenfalls schicker als das normale ADO.NET Thema. Wenn man das allerdings ausprobiert, bekommt man eine Fehlermeldung:

image

Erstmal die Entwarnung: Es geht – mit einem kleinen Trick.

Doch langsam: Vorbereitung

Als erstes benötigen wir eine "Local Database":

image

Diese SQL Server Compact Edition Database erkennt man an der "sdf" Endung. Nachdem wir dies gemacht haben, kommt so ein Dataset Dialog – den einfach ignorieren und schließen. 

Jetzt legen wir unsere Tabellen an – der Dialog ist ähnlich wie beim SQL Management Studio:

image

Nachdem wir  nun eine Company Tabelle ("Id" = Guid, "Name" = nvarchar) & Employee ("Id" = Guid, "Firstname" = nvarchar, "Lastname" = nvarchar, "CompanyId" = Guid) können wir über ein Kontextmenü die Verknüpfung zwischen den beiden Tabellen einstellen:

image

Das entsprechende Menü:

image

Nachdem wir das haben, kommen wir nun zum eigentlichen Teil:

LINQ to SQL einsetzen

Bei einer normalen MDF oder einer SQL Server Tabelle kann man den Designer nehmen, allerdings ist dies momentan bei einer Compact Edition DB nicht möglich.

Allerdings gibt es ein kleines Tool namens "SQLMetal.exe", welches normalerweise unter diesem Pfad zu finden ist:
C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin

Die Datei "SQLMetal.exe" sowie die Config Datei habe ich einfach mit in mein Projektverzeichnis kopiert.

Danach wird es wie folgt aufgerufen:
SqlMetal.exe Database.sdf /dbml:Enterprise.dbml /namespace:SQLCompact /pluralize

Folgendes passiert: Die Database.sdf wird aufgerufen und es wird eine Enterprise.dbml erstellt – im Namespace "SQLCompact".

DBML dem Projekt hinzufügen

Damit man es im Projekt nutzen kann, muss man es noch einblenden:

image

… und am Ende sieht man sowas:

image

Müsste eigentlich bekannt vorkommen, oder? ;)

Beispiel: Datensatz einfügen

Der Datacontext kann entweder über die verschiedenen Parameter anders benannt werden oder ist im Standardfall gleich mit dem sdf Namen. Sodass wir nun mit dem Code eine neue Firma einfügen können:

image

Also alles nix neues – der Connectionstring kann vom Serverexplorer unter "Eigenschaften" ausgelesen werden oder von dieser Website.

Jetzt können wir alles anwenden, was wir z.B. hier oder hier kennengelernt haben.

Hier gibts noch ein paar LINQ Informationen.

Viel Spaß :)

[Download Source Code]

HowTo: LINQ to XML – Daten lesen

LINQ to SQL (siehe hier & hier) habe ich bereits behandelt, doch einer der mitgelieferten LINQ Provider wurde von mir noch vernachlässigt: LINQ to XML.

Ohne LINQ kann man XML über XPath abfragen – das ist eine nette Variante, allerdings vielleicht nicht unbedingt der Weisheits letzter Schluss.

Fangen wir mal langsam an – hier unsere einfache XML Struktur:

image

Wenn man diesen Zweig nun abrufen will, geht folgender Code:

image  
(auf meinem neuen Notebook konnte ich leider noch nicht das CodeFormatting Plugin für den Windows Live Writer installieren – daher nur Screenshots und am Ende gibts den Source Code)

XDocument etc. ist in dem Namespace System.Xml.Linq vorhanden und ist im Grund wie das XmlDokument – natürlich etwas anders. Über die Methode "Descendants" können wir uns entweder (wie oben) manuell durch den Xml Baum hangeln, oder direkt auf das "Item" zugreifen:

image

Ist doch schon wesentlich eleganter, oder? Als Ergebnis bekommen wir bei dieser LINQ Abfrage die XElemente:

image

Jeder Node hat eine "Number" Element, was bei dem ersten Item auf 10, beim zweiten auf 50, beim dritten auf 60 und beim vierten Item auf 70 gesetzt wurde.

Jetzt wollen wir nur mal alle Items heranholen, welche über 55 liegen:

image

Wir navigieren uns wieder zu unseren Items und machen dann anschließend eine Konvertierung des Values im "Number" Tag zu einem Integer.

Am Ende werden nur noch die letzten beiden Item Einträge angezeigt.

Mal etwas komplizierter – Attribute, Verschachtelungen & Abfragen:

Unsere etwas komplexere XML Struktur:

image

Mit dieser LINQ Abfrage bekommt man alle komplexen Items, welche als Attribut "marketplace" "fr" haben und die Number größer als 20 ist:

image

Fazit:

LINQ to XML ist eine schicke Alternative zu normalen XPath und erlaubt sehr viele Spielerein. Wenn ich zeit finde, zeige ich auch noch, wie man XML Dokumente bearbeitet. Man kann das ganze natürlich noch weitertreiben. In dem select Statement kann man sich seine eigenen Datentypen erstellen etc. (dank an das Zauberwort "var").

Insbesondere für diejenigen, welche einen RSS/Atom Feedreader entwickeln wollen, sollten mal auf LINQ to XML einen Blick werfen.

Hier einen weiterführenden Link:

[ Download Source Code ]

GUIDs vs. auto-increment IDs

Ich oute mich mal als ein “ehemaliger” PHP Entwickler. MySQL ist natürlich die Standarddatenbank für PHP Anwendungen. Man macht über phpmyadmin (ich war noch jung und kannte nichts anderes ;) ) seine Datenbanken und wie es sich so gehört, hat jeder Datensatz in einer X-beliebigen Tabelle eine eindeutige ID. Die “ID” Spalte wird einfach ein Integer und setzt diese als den primären Schlüssel und schaltet noch ein, dass diese Spalte automatisch hochgezählt werden soll.

So für sich gesehen, ist es recht simpel und funktioniert gut. Dieses Prinzip wird aber dann schwieriger umzusetzen, wenn bestimmte Abhängigkeiten zu anderen Tabellen bestehen sollen.

Aber erstmal ganz langsam… unser Szenario:

Wir haben Produkte, welche wir in eine “Products” Tabelle speichern:

  • Id
  • Name
  • Price

Jedes Produkt kann ähnliche Produkte haben, welche in einer “ReleatedProducts” Tabelle gespeichert wird:

  • Id (diese Spalte könnte man auch weglassen – spielt aber jetzt keine große Rolle).
  • ProductFirstId
  • ProductSecondId

Wir haben jetzt ein Anwendung, in dem wir 2 Produkte erstellen wollen und diese in Beziehung setzen. Wenn wir dies jetzt mit “normalen” autoincrement IDs umsetzen, wird es etwas knifflig…

Warum? Das geht ganz einfach…

Natürlich geht das mit dem autoincrement IDs. Allerdings muss man quasi folgende Schritte machen:

  1. Erstes Produkt erstellen
  2. Erstelltes Produkt in die DB speichern
  3. Eben erstellte ID als Rückgabewert bekommen
  4. Zweites Produkt erstellen
  5. Erstelltes Produkt in die DB speichern
  6. Eben erstelle ID als Rückgabewert bekommen
  7. Beziehung setzen mit den beiden Rückgabewerten

Das ist nur teilweise schön – das liegt nunmal an der Natur von autoincrement IDs:

Die Verwaltung der eindeutigen IDs wird der Datenbank überlassen!

Man kann nicht 100% die nächste ID erraten. Wenn man nun einen Datensatz mit einem anderen Verknüpfen möchte, muss man vorher immer die DB befragen. Falls in der Zwischenzeit was schief geht und auch keine referenzielle Integrität angeschaltet ist, bleiben im schlimmsten Falle leichen übrig.

Was gibts für eine Alternative?

GUIDs bieten eine nette Abhilfe und sind insbesondere im Microsoft Umfeld stark vertreten.

Im .NET Framework gibt es direkt eine GUID Klasse zum Erzeugen solcher IDs. Im SQL Server ist der Datentyp “uniqueidentifer” dafür vorgesehen.

Was sind die Vorteile?

  • Die Kontrolle der eindeutigen IDs kann direkt im Programm gesteuert werden.
  • Die Daten brauchen erst zur DB gespeichert werden, wenn dies nötig ist.
  • Bei einer evtl. Zusammenführung von 2 Tabellen hat man das ID Problem nicht.

Was sind die Nachteile?

  • Performance? Jedenfalls aus dem Microsoft SQL Lager hört man sowas nicht – zwar ist eine GUID länger als eine “normale” ID, allerdings fällt dies kaum ins Gewicht.
  • Ids sind etwas unschöner und man kann schlechter nachvollziehen und mal einzelne Daten Testen:
    • Webseiten mit …?id=2312 sind (wie z.B. bei Wordpress) durch konkrete Titel ersetzt wurden – die IDs “sieht” der Benutzer (oder die Suchmaschine) kaum. Das man einzelne Daten schlechter Nachverfolgen kann, ist allerdings wahr.

Demoprojekt nötig?

Ich habe ein Demoprojekt mit VS 2008 Express Edition und LINQ to SQL erstellt – dort wird einmal mit GUIDs und ohne GUIDs gearbeitet – allerdings habe ich nur den GUID Teil bis zum Ende geführt – weil es für mich simpler war ;)

Der ConnectionString muss natürlich angefasst werden:

[ Download Democode ]

Buchüberblick Januar 2008 – .NET 3.5, ASP.NET 3.5, AJAX, ADO.NET, LINQ

Das .NET Framework in der Version 3.5 ist schon eine Weile draußen und da ich selber immer auf der Suche nach aktuellen Büchern bin, hier eine aktuelle Auswahl oder kommenden Büchern – Haupthema ist ASP.NET 3.5, .NET 3.5, AJAX oder LINQ.

Deutschsprachige:

Englischsprachige:

Das ganze natürlich noch als schickes Widget ;)

HowTo: O/R Mapper LINQ to SQL – Einführung in den Designer & 1:N Beziehungen

Im letzten HowTo rund um LINQ to SQL ging es mehr darum, ein Grundverständnis zu vermitteln. Das manuelle Mapping ist eine Methode, wie man LINQ to SQL nutzen kann – mit Visual Studio 2008 (selbst in der Express Edition) ist auch ein LINQ to SQL Designer Template mit dazugekommen:

image

Variante A: Unser einfaches Costumer Beispiel diesmal mit dem Designer

Schritt 1: .dbml Datei erstellen

Nachdem eine solche “xxx.dbml” Datei erstellt hat – in unserem Beispiel wollen wir wieder die Costumer Tabelle aus der Northwind Database auslesen (Installationsanleitung), daher “Costumers.dbml” – sieht man nur eine solche Meldung:

image

Schritt 2: DB Verbindung hinzufügen

Über den DB Explorer legen wir eine Verbindung zu einem Microsoft SQL Server Database File her:

image

Danach wählen wir unserer Northwind.MDF (Standardinstallationspfad: “C:\SQL Server 2000 Sample Databases\NORTHWND.MDF”).

Schritt 3: Tabellen auf die Designer Oberfläche ziehen

Im nächsten Schritt ziehen wir einfach die jeweiligen Tabellen die wir haben wollen (in unserem Fall die Costumers) auf die Oberfläche:

image

Visual Studio 2008 erstellt daraufhin folgende Sturktur:

image

  • Customer.dbml.layout = XML Beischreibung
  • Costomer.dbml.cs = Der eigenliche Code mit sämtlichen Attributen und dem

Allerdings landet in der Customer.designer.cs nicht nur wie bei dem vorherigen HowTo die MappingInformationen der Tabelle, sondern es wird zugleich auch gleich eine spezielle DataContext Klasse “CostumerDataContext” gebildet:

 

image

Die Interfaces INotifyPropertyChanging & INotifyPropertyChanged wurden ebenfalls implementiert – WPF benutzt dies zum Beispiel im Kontext mit Databinding, was hier ja quasi ebenfalls passiert.

 Schritt 4: Daten abrufen, verändern und löschen

Jetzt können wir die selben Befehle ausführen, wie in unserem anderen Beispiel:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
using System.Text;

namespace LinqToSqlDesigner
{
    class Program
    {
        static void Main(string[] args)
        {
            CustomerDataContext context = new CustomerDataContext();
            Table<Customer> customerTable = context.GetTable<Customer>();

            var customerResult = from customer in customerTable
                                 where customer.City == "London"
                                 select customer;

            foreach (Customer oneCustomer in customerResult)
            {
                Console.WriteLine(oneCustomer.CompanyName);
            }

            Console.ReadLine();

        }
    }
}

Diese Variante ist so nicht zu empfehlen – jedenfalls sollte die dbml nicht nach einer Tabelle genannt werden. In der nächsten Variante sieht man gut, wie man eine größere Datenbank mit einer dbml abbilden kann.

Variante B: 1:N Beziehungen mit dem Designer

Das war ja jetzt nicht sonderlich spannend, allerdings ist es auch möglich direkt im Designer 1:N Beziehungen vorzunehmen.
Dazu erstellen wir uns wieder unsere LINQ to SQL “Northwind.dbml” und wählen jetzt mal den Customers und die Orders aus:

image
Der “Pfeil”, also die Association, zwischen CustomerID aus der Customer Klasse/Tabelle und der CustomerID aus der Order Klasse/Tabelle wird automatisch gebildet (wahrscheinlich weil diese Assoziation bereits im DB System bekannt ist – ob das Mapping auch anhand des Namens erfolgt, habe ich momentan nicht getestet). Man kann diese Assoziation allerdings auch selber bearbeiten, indem man in den Eigenschaften des “Pfeils” schaut:

image

Eigenschaften:

image

Der LINQ to SQL O/R  Designer besitzt ebenso eine eigene Toolbox, mit welchen man auch einige eigene Sachen erstellen kann:

image

Wenn man nun noch zwei weitere Tabellen in den Designer zieht, macht das langsam einen recht schicken Eindruck:

image

Dadurch habe wir innerhalb weniger Minuten bereits folgende fertige Klassen zur Verfügung:

image

Jetzt machen wir mal wieder unsere Abfrage um zu zeigen, was man damit machen kann:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;

namespace LinqToSqlDesigner
{
    class Program
    {
        static void Main(string[] args)
        {
            NorthwindDataContext context = new NorthwindDataContext();
            Table<Customer> customerTable = context.GetTable<Customer>();

            var cust = from c in customerTable
                       where c.City == "London"
                       select c;

            foreach(Customer customer in cust)
            {
                Console.WriteLine(customer.CompanyName);
                if(customer.Orders.Count > 0)
                {
                    Console.WriteLine("Customer Orders");
                    foreach(Order order in customer.Orders)
                    {
                        if(order.Order_Details.Count > 0)
                        {
                            Console.WriteLine(" - " + order.Order_Details[0].Product.ProductName);
                        }
                    }

                }
            }

            Console.ReadLine();
        }
    }
}

Hierbei holen wir uns erst alle Kunden aus “London”, welche wir auf der Konsole ausgeben. Danach prüfen wir, ob der Kunde eine Bestellung offen hat und welche dazugehörige Produkte er dazu gekauft hat. Resultat:
image

Was verbirgt sich hinter den 1:N Beziehungen?

Wenn wir jetzt mal in den generierten Code reinschauen, z.B. bei der Customer Klasse, finden wir folgenden Abschnitt:

      private EntitySet<Order> _Orders;

        public Customer()
        {
            this._Orders = new EntitySet<Order>(new Action<Order>(this.attach_Orders), new Action<Order>(this.detach_Orders));
            OnCreated();
        }

Ein “EntitySet” (Streng Typisiert) dient dabei als Datenspeicher der Beziehungsdaten. Das Gegenstück von EntitySet ist EntityRef.

Schematisch wäre dies grob so:

image

Der Customer hat Orders in seinem EnitySet gespeichert. Die Orders halten wiederrum die Verweise als EntityRef fest. Nachzulesen lässt sich das (und auch das Thema Many-to-Many-Relations, auch in der MSDN: How to: Map Database Relationships (LINQ to SQL)

Natürlich kann man auch mit dieser Basis die ganzen CRUD Sachen aus diesem Blogpost machen.

Fazit

LINQ to SQL bietet einen sehr netten Designer, mit dem man schnell zu Ergebnissen kommt. Wie ich selber aber gemerkt habe, ist sicherlich erst eine Grundsätzlich Einarbeitung in den Abfrage Syntax von LINQ notwenidig um gute und performante Abfragen zu gestalten.

Jeder der mit Microsoft SQL und .NET 3.5 zutun hat, sollte sich die Möglichkeiten von LINQ to SQL nicht entgehen lassen!
Es gibt sicherlich noch mehr Themen rund um LINQ to SQL – das war ja auch erst der zweite Post zu diesem Thema ;)

Downloaden könnt ihr das Testprojekt auch, allerdings musste ich aus Platzgründen die Northwind.mdf (und die log Datei) aus dem Verzeichnis entfernen – installiert die Northwind Datenbank einfach und kopiert die beiden Datein mit in das Verzeichnis. Visual Studio 2008 (mit Administrator Rechten) ist bei .NET 3.5 Pflicht.

[ Download Sourcecode ]

HowTo: O/R Mapper LINQ to SQL – Einführung & einfaches manuelles Mapping

LINQ to SQL ist Microsofts LINQ Provider für das Hauseigene Datenbanksystem SQL Server 2005 (und 2008 – und noch mehr?). Das Konzept von LINQ sollte man vorher bereits verstehen – hier eine Kurzeinführung:

LINQ? Was ist das?

In jeder Applikation arbeitet man mit Daten, Objekten und noch mehr Ansammlungen von Objekten. Externe Datenquellen (XML, Datenbanken) muss man über ihre jeweiligen Abfragesprachen ansprechen – SQL oder XPath. Objektcollections oder komplexe Objekte in C# 2.0 haben kein solches Abfragesystem gehabt – man musste über Foreach-Schleifen die Collections durchgehen und dann immer wieder mit dem Suchwort vergleichen.

Hier tritt LINQ ins Spiel – LINQ erlaubt es, .NET Objekte mit einem SQL ähnlichen Syntax zu durchsuchen, allerdings mit allen Vorteilen die Visual Studio und Objekte bieten: Einfaches Debugging möglich, man arbeitet mit direkten Objekten und die IntelliSense hilft natürlich auch kräftig. Am Ende einer LINQ Abfrage kann man direkt ein “var” Objekt erzeugen (was das ist, wurde hier besprochen). Da man nicht nur Objekte so durchsuchen kann, sondern auch andere Daten, zeigt z.B. der LINQ to XML oder der LINQ to SQL Provider.

Microsoft hat LINQ so gestaltet, dass viele solche Provider erstellt werden können, sodass es momentan z.B. folgene Provider in Entwicklung befinden:

Wir beschäftigen uns heute mit LINQ to SQL – dabei werden wir einmal nur in einer sehr einfachen Abfrage LINQ to SQL anschauen und später ein etwas komplexeres Mapping per Hand vornehmen.
Der LINQ to SQL Designer wird später behandelt!

Vorbereitung & Dokumente

Ich halte mich hier an das Hand on Lab von Microsoft, welches es hier kostenlos zum Runterladen gibt. Desweiteren benötigen wir die Northwind Datenbank – eine Installationsanleitung gibt es hier. Natürlich benötigen wir Visual Studio 2008 Express Edition. Visual Studio und das SQL Management Studio sollten im Administratormodus laufen (und bei meinem Demoprojekt muss hinterher der ConnectionString angepasst werden)

Erster Schritt mit LINQ to SQL

Als erstes benötigen wir die System.Data.Linq.dll, damit wir die entsprechenden Namespaces verwenden können.
Danach erstellen wir unser erstes Mapping (wie bereits oben erwähnt, werden wir hier ein manuelles Mapping vornehmen um das System besser zu verstehen).

Schauen wir uns mal die Tabellen der Northwind Datenbank an:

image

Wir wollen einfach eine kleine Konsolen-Applikation haben, welche die Kundendaten bearbeitet.

LINQ to SQL – Schritt 1: Das Mapping

Die Kundendaten stehen in der “Customers” Tabelle – daher legen wir eine “Customers” Klasse an:

image

Dabei verwenden wir den Namespace “System.Data.Linq.Mapping” in der “Customer.cs”.
Das Mapping erfolgt über das Zuweisen von Attributen zu der Klasse (das Table Attribut) und den Properties (das Column Attribut).

Quellcode sagt meist mehr als tausend Wort:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq.Mapping;

namespace LinqToSqlTest
{
    [Table(Name = "Customers")]
    public class Customer
    {
        [Column(IsPrimaryKey = true)]
        public string CustomerID;

        [Column]
        public string Address { get; set; }

        private string _City;

        [Column(Storage = "_City")]
        public string City
        {
            get { return this._City; }
            set { this._City = value; }
        }
    }

}

Erklärung:

Das Mapping erfolgt durch die Zuweisungen der entsprechenen Attribute (Attribute-based Mapping) – beim Klassennamen “Customer” wird das Tabel Attribut verwendet – das “Name” dort verbindet die “Costumers” Tabelle mit dieser Klasse. Der Name kann auch weggelassen werden, wenn DB Tabellennamen == Klassenname (in unserem Fall fehlt ein “s” im Klassennamen).
Die einzelnen Spalten werden über das Column Attribut den Properties zugewiesen (MSDN Artikel: How to: Represent Columns as Class Members (LINQ to SQL)).

Das Mapping erfolgt hierbei wieder anhand des Namens der DB Spalte und des entsprechenden Properties. Falls dies abweicht, gibt es noch ein Name Property (wie bei dem Tabellen Attribut oben).
Standardmäßig wird dann der DB Wert in das Property geschrieben, welches zugewiesen wurde. Wenn man als Datenhalterobjekt z.B. ein privates Property verwenden möchte, kann man dies über das “Storage” Property zuweisen.

LINQ to SQL – Schritt 2: Die DB Abfrage

In unserer Program.cs wollen wir nun eine einfache Abfrage der Kunden einbauen.

Als erstes müssen wireinen DataContext aufbauen, welchen wir den ConnectionString übergeben. Danach veranlassen wir den Datacontext das Mapping über die GetTable Methode zu “starten”:

DataContext db = new DataContext(@"Data Source=REMAN-NOTEBOOK\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");
Table<Customer> Customers = db.GetTable<Customer>();

Um zu sehen, was für SQL Befehle ausgeführt werden, gibt es auch ein Log Property, wo wir unsere Console anheften:

db.Log = Console.Out;

Jetzt zur eigentlichen Abfrage mit LINQ (und der Ausgabe):

            var custs =
                from c in Customers
                where c.City == "London"
                select c;

            foreach (var cust in custs)
            {
                Console.WriteLine("ID={0}, City={1}, Address={2}", cust.CustomerID, cust.City, cust.Address);
            }

Mit der Abfrage werden alle Kunden aus London in “var custs” (das Konzept von “var” ist hier beschrieben) gespeichert.

Hinweis: Mit GetTable<…>() werden noch keine Daten vom SQL Server geholt – erst beim Zugriff auf Customers wird die Abfrage gemacht (Siehe Video).

Ergebnis:

image

Vollständiger Quellcode:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Data.Linq.Mapping;

namespace LinqToSqlTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // Use a standard connection string
            DataContext db = new DataContext(@"Data Source=REMAN-NOTEBOOK\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");
            Table<Customer> Customers = db.GetTable<Customer>();

            db.Log = Console.Out;

            // Query for customers in London
            var custs =
                from c in Customers
                where c.City == "London"
                select c;

            foreach (var cust in custs)
            {
                Console.WriteLine("ID={0}, City={1}, Address={2}", cust.CustomerID, cust.City, cust.Address);
            }

            Console.ReadLine();
        }
    }
}

LINQ to SQL – Schritt 3: Änderung an der DB vornehmen – einen neuen Eintrag anfügen

Ein neuen Eintrag hinzufügen geht recht schnell:

            Customer newCostumer = new Customer();
            newCostumer.City = "Dresden";
            newCostumer.Address = "Riesaer Str. 5";
            newCostumer.CustomerID = "DDMMS";
            newCostumer.CompanyName = "T-Systems MMS";

            Customers.InsertOnSubmit(newCostumer);
            db.SubmitChanges();

Hierbei musste ich aber noch ein neues Property für den Costumer hinzufügen: CompanyName – weil dieser (ebenso wie CustomerID) NOT NULL sein muss:

image

Wie oben zu sehen ist, wird einfach ein neuer Customer angelegt und über Customers wird dieses Objekt an (die wir über den DataContext bekommen haben) die Methode “InsertOnSubmit” weitergereicht und dort vorgemerkt, beim “Submitten” in die DB eingetragen zu werden.

Das “Submitten” wird über “SubmitChanges” vom DataContext gestartet.

LINQ to SQL – Schritt 4: Änderung an der DB vornehmen – einen Eintrag editieren

Das Dateneditiere wird direkt an den Objekten vorgenommen:

            var upObjects = from test in Customers
                             where test.CompanyName == "T-Systems MMS"
                             select test;

            upObjects.First().Address = "Straße";
            db.SubmitChanges();

Hier erfolgt nur ein “SubmitChanges” und der erste gefundene Eintrag (über First()) wird entsprechend geändert.

LINQ to SQL – Schritt 5: Änderung an der DB vornehmen – einen Eintrag entfernen

Den eben angelegten Eintrag kann man auch wieder entfernen:

var delObjects = from test in Customers
                             where test.CompanyName == "T-Systems MMS"
                             select test;

            Customers.DeleteOnSubmit(delObjects.First());
            db.SubmitChanges();

Hier holen wir uns einfach unser eben erstelltes Objekt wieder und nehmen wieder über die First() Methode das erste gefundene (da es sowieso nur einen Eintrag dort gibt) Ergebnis. Löschen kann man es einfach über “DeleteOnSubmit“.

Der gesamte Source Code (download weiter unten):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Data.Linq.Mapping;

namespace LinqToSqlTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // Use a standard connection string
            DataContext db = new DataContext(@"Data Source=REMAN-NOTEBOOK\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True");
            Table<Customer> Customers = db.GetTable<Customer>();

            // Logging
            db.Log = Console.Out;

            // CREATE
            Customer newCostumer = new Customer();
            newCostumer.City = "Dresden";
            newCostumer.Address = "Riesaer Str. 5";
            newCostumer.CustomerID = "DDMMS";
            newCostumer.CompanyName = "T-Systems MMS";

            Customers.InsertOnSubmit(newCostumer);
            db.SubmitChanges();

            // READ
            var custs =
                from c in Customers
                where c.City == "Dresden"
                select c;

            // Debugging - Console.WriteLine
            foreach (var cust in custs)
            {
                Console.WriteLine("ID={0}, City={1}, Address={2}", cust.CustomerID, cust.City, cust.Address);
            }

            // UPDATE
            var upObjects = from test in Customers
                             where test.CompanyName == "T-Systems MMS"
                             select test;

            upObjects.First().Address = "Straße";
            db.SubmitChanges();

            // Debugging - Console.WriteLine
            foreach (var cust in custs)
            {
                Console.WriteLine("ID={0}, City={1}, Address={2}", cust.CustomerID, cust.City, cust.Address);
            }

            // DEL
            var delObjects = from test in Customers
                             where test.CompanyName == "T-Systems MMS"
                             select test;

            Customers.DeleteOnSubmit(delObjects.First());
            db.SubmitChanges();

            Console.ReadLine();
        }
    }
}

Wichtiger Hinweis:

Die Anwendung läuft nur einmal durch, da die CustomerID eindeutig sein muss – aber das hier soll nur der Anfang sein um LINQ to SQL mehr zu verstehen.
Das die LINQ Abfragen hier sicherlich verbesserungswürdig sind, ist eine andere Sache (und wird sicherlich in einem anderen HowTo unterkommen).

Das Mapping erfolge hier sehr einfach über das manuelle dazu schreiben der Attribute – es gibt einen direkten LINQ to SQL Designer.

Empfehlung an alle die sich für LINQ to SQL interessieren:

Das HoL über LINQ to SQL, was ich bereits oben erwähnt hatte, geht noch auf andere Aspekte ein. Einige davon werde ich sicherlich selber noch in HowTos packen, allerdings bis dahin dient es als gute Anlaufstelle zu Themen wie:

  • LINQ to SQL Designer
  • Beziehungen zwischen einzelnen Tabellen modellieren
  • Streng-typisierte DataContext Objekte
  • Transaktionen (Sehr interessantes Thema!)
  • Mapping a stored procedure

Das Thema wird sicherlich bei mir noch häufiger anzutreffen sein (und das war heute mein erster richtiger Berührungspunkt mit LINQ to SQL – ich hoffe, dass das Konzept (und wie es intern tickt) etwas klarer ist ;) )

[ Download Demoanwendung ]

HowTo: C# 3.0 – "var" Keyword und andere kleine C# 3.0 Features verstehen

Mit .NET 3.5 kam auch C# 3.0 (und die entsprechende VB Variante, die hier aber nicht behandelt wird) ans Licht der Welt. Für die Entwicklung von .NET 3.5 Applikationen ist Visual Studio 2008 Pflicht – die Express Variante kann man sich kostenlos bei Microsoft runterladen.

In diesem HowTo geht es um das neue Keyword “var“, andere Featues wie Lamda Expressions, LINQ, Partielle Methoden werden später bestimmt ebenfalls noch Themen werden.

Für einen gute Komplettübersicht empfehle ich das C# 3.0 Language Enhancements Hands on Lab.

Was ist “var”?

Mittels “var” ist es möglich einem Object einen anonymen Typ zuzuweisen. Dabei weist der Compiler dann eine entsprechende Klasse oder eine anonyme Klasse zu. Trotz dessen, ist das Object immernoch typisiert. Am besten sieht man dies an einem kleinen Beispiel:

 var IntVar = 15;
 var StringVar = "Hello";
 var ComplexVar = new DateTime();

“IntVar” wird automatisch zum Typ “int”, “StringVar” zu “string” und “ComplexVar” zu “DateTime”. Beweis:

image

Ein einmal zugewiesener Typ, kann nur durch Casting oder Ähnliches in einen anderen Typ konvertiert werden – also wie früher:

var IntVar = 15;
IntVar = 13.5;

Dies bringt folgenden Fehler beim Kompilieren:

image

Wofür braucht man “var” dann?

Wenn man am Ende trotzdem nur einmal den Typ festlegen kann, wozu sollte ich dann überhaupt “var” schreiben, wenn ich gleich “string” etc. hinschreiben könnte?
Folgender Sachen sind mit “var” möglich und daher in diesen Fällen auch interessant:

  • 1. In Zusammenhang mit LINQ kann man sich sein “Result” Typ so zusammenbauen, wie man ihn braucht, ohne das er vorher existierte.
  • 2. Man kann einen komplexes Objekt “on-the-fly” erstellen.

Eine Sache sollte natürlich klar sein: “var” sollte nur dort Verwendung finden, wo es sinnvoll ist – wenn der Typ ohnehin bekannt und da ist, braucht man es schonmal nicht.

Das Demoprojekt – ein Konsolenprogramm zum Testen der neuen Features

Nachfolgend müssen wir einige Sachen vorbereiten, um am Ende das “var” Keyword sinnvoll zu gebrauchen.

Als erstes brauchen wir mal eine kleine Klasse, damit wir etwas experimentieren können:

    public class Product
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }

C# 3.0 Neuerung hierbei: Das Feature mit “get; set;” ist ebenfalls neu in C# 3.0. Damit entfällt das etwas lästige “private string blub; public string Blub {…}” –

Danach legen wir in “Main” ein neues Produkt an:

Product MyProduct = new Product { Name = "Auto", Id = 123 };

C# 3.0 Neuerung hierbei: Ebenfalls neues Feature und wird in Visual Studio 2008 auch über die IntelliSense angezeigt:

image 

Und auch eine Liste an Produkten wird angelegt:

List<Product> MyProductList = new List<Product>
            {
                new Product { Name = "Brett", Id = 1 },
                new Product { Name = "Bett", Id = 2 },
                new Product { Name = "Pfanne", Id = 3 }
            };

C# 3.0 Neuerung hierbei: Auch Listen oder Arrays können so angelegt werden. Alles natürlich mit IntelliSense.

Dann legen wir noch 2 andere Objekte an:

var MyVarString = "Something...";
var MyVarInt = 13;

C# 3.0 Neuerung hierbei: Wie bereits oben geschrieben – das “var” Keyword.

Das “var” Keyword benutzen, um einen komplexen anonymen Typ zu erstellen

            var MyVarComplex = new {
                                    Product = new Product { Name = "Kette", Id = 33},
                                    AnotherProduct = MyProduct,
                                    SimilarProducts = MyProductList,
                                    Information = "This is an additional information.",
                                    SpecialId = MyVarInt,
                                    SpecialString = MyVarString
                                };

 

“MyVarComplex” ist nun unser komplexer, anonymer Typ, welchen wir on-the-fly über das “var” Keyword erstellen:

Über “new { … }” legt man einen solchen anonymen Typ an. “AnotherProduct” ist z.B. eines unserer Attribute des anonymen Typs und wird mit “MyProduct” befüllt.

image

Besonders interessant: “MyVarComplex” wird als “Anonymous Type” angegeben.

Natürlich bietet Visual Studio volle IntelliSense Unterstützung:

image 

Was haben wir jetzt davon?

Manchmal benötigt man Daten in einer speziellen Form, von verschiedenen Objekten – bis jetzt musst man entweder über unschönen Notlösungen mit “object” oder halt das erstellen einer entsprechenden Klasse sowas lösen. Mit “var” ist es jedoch sehr einfach, einen entsprechenden Objektbaum schnell zu erstellen.
Zusammen mit den anderen C# 3.0 Features die hier vorgestellt wurden, aber auch LINQ und co., ist das ein großer Schritt nach vorn.

Hier der gesamte Source Code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CSharp3
{
    class Program
    {
        static void Main(string[] args)
        {
            Product MyProduct = new Product { Name = "Auto", Id = 123  };

            List<Product> MyProductList = new List<Product>
            {
                new Product { Name = "Brett", Id = 1 },
                new Product { Name = "Bett", Id = 2 },
                new Product { Name = "Pfanne", Id = 3 }
            };

            var MyVarString = "Something...";
            var MyVarInt = 13;

            var MyVarComplex = new {
                                    Product = new Product { Name = "Kette", Id = 33},
                                    AnotherProduct = MyProduct,
                                    SimilarProducts = MyProductList,
                                    Information = "This is an additional information.",
                                    SpecialId = MyVarInt,
                                    SpecialString = MyVarString
                                };

            Console.ReadLine();
        }
    }

    public class Product
    {
        public string Name { get; set; }
        public int Id { get; set; }
    }
}

Als Download:

[ Download Democode ]

Links:

Microsoft Press verschenkt LINQ, ASP.NET AJAX und Silverlight 1.0 e-Books

Zur Weihnachtszeit gibts was sehr interessantes von Microsoft Press: 3 EBooks gratis (Voraussetzung ist nur eine Windows Live ID)

Downloaden könnt ihr das ganze auf der Microsoft Learning Website (dort ist ein Link “Download Free e-book offer…” – da drauf klicken und Windows Live ID und noch wenige andere Angaben machen) – Topaktuelle Bücher kostenlos ist doch immer schön.

Gefunden habe ich dies auf einem Schweizer MSDN Blog.

In dem Zusammenhang möchte ich nochmal die laufende Aktion von Entwickler-Press erwähnen – bis zum 24. ist es zwar nicht mehr lang, aber ein paar Bücher kann man sich noch runterladen.

Release of .NET Framework 3.5 & Visual Studio 2008

image

Bereits in dem gestriegen Post habe ich bereits den Release des .NET Frameworks 3.5 samt VS 2008 mit angeschrieben.

Heute möchte ich gleich auf den Post von Scott Guthrie verweisen, welcher offiziel das .NET 3.5 und VS 2008 veröffentlicht hat. Mit inklusive in diesem doch recht langen Post sind alle neuen Features und ein interessantes HowTos zu LINQ.

Zudem stellt Microsoft ein Tranings-Kit mit verschiedenen Präsentationen / Hand-on-labs etc. im Microsoft Downloadbereich zur Verfügung.

[ .NET Framework Direktdownload ] [ Visual Studio Express Editions Download ] [ Visual Studio Team Foundation Trial ]