Freitag, 2. September 2011

Select Top-Rows per SQL

Gerade brauchte ich für einen schnellen Test mal wieder einfach nur ein paar Datensätze aus einer Datenbank.
Die schnellste Art und Weise dieses zu realisieren ist, wenn man einfach nur die ersten x Zeilen ausliest.
Diese könnte man ggf. für bestimmte Auswertungen auch direkt sortiert ausgeben. Aber für meine Tests war das völlig egal.

Da ich ständig mit dem MS SQL-Server arbeite habe ich meine Abfrage wie folgt geschrieben.

-- Rückgabe der ersten 5 Zeilen aus Tabelle1
SELECT TOP 5 * FROM Tabelle1

Bei meinem aktuellen Test habe ich jedoch eine Oracle Datenbank abgefragt.
Nach der Ausführung des oben stehenden SQL-Statements habe ich jedoch folgenden Fehler bekommen.
Error starting at line 1 in command:
SELECT TOP 5 * FROM Tabelle1
Error at Command Line:1 Column:11
Error report:
SQL Error: ORA-00923: Schlüsselwort FROM nicht an erwarteter Stelle gefunden
00923. 00000 -  "FROM keyword not found where expected"
*Cause:   
*Action:

Nach kurzer Überlegung ist es mir direkt wieder eingefallen. Oracle kennt keinen TOP-Befehl.
Dafür gibt es in Oracle-Datenbanken jedoch die Spalte "rownum". Mit dieser kann man dann nicht nur Top-Werte sondern auch ganz bestimmte Datensätze wie folgt ausgeben lassen.

-- Rückgabe der ersten 5 Zeilen aus Tabelle1
SELECT * FROM Tabelle1 WHERE rownum <= 5

-- Rückgabe der Zeilen 6 bis 10 aus Tabelle1
SELECT * FROM Tabelle1 WHERE rownum > 5 AND rownum <= 10

Donnerstag, 11. August 2011

Builderror bei MonoTouch-Projekten mit EGOPhotoViewController

In einem aktuellen MonoTouch-Projekt habe ich für die Anzeige einer Bildergalerie das kleine externe Framework EGOPhotoView/EGOPhotoViewController eingebunden. Nach der Implementierung konnte ich das Projekt nicht mehr kompilieren. Es kam im Output immer folgender Fehler:

Undefined symbols:
"__Unwind_Resume", referenced from:
+[EGOCache currentCache] in libPhotoViewerKitMobile.a(EGOCache.o)
-[EGOCache saveCacheDictionary] in libPhotoViewerKitMobile.a(EGOCache.o)
+[EGOImageLoader sharedImageLoader] in libPhotoViewerKitMobile.a(EGOImageLoader.o)
ld: symbol(s) not found
collect2: ld returned 1 exit status
Process exited with code 1, command:

Abhilfe hat hier folgende Einstellung geschaffen:
- Projekteigenschaften öffnen
- Build => IPhone Build auswählen
- Im Reiter "General" die "Additional mtouch arguments" erweitern um -gcc_flags "-cxx -lgcc_eh"

Tipp:
Um erweiterte Ausgabemeldungen (Output) zu bekommen, muss man einfach in die arguments noch die Parameter -v -v -v aufnehmen.

Mittwoch, 10. August 2011

Zufalls-Datensätze direkt per SQL auslesen

Manchmal benötigt man schnell und einfach einen einzelnen, beliebigen Datensatz aus einer Datenbank/Tabelle. Wo mir dieses bislang sehr nützlich erschien, war zum Beispiel beim Einlesen von Zufallsbildern auf mobilen Geräten. Um hier keinen unnötigen Overhead wie das Erstellen von Objekt-Id-Listen zu erzeugen, ist es manchmal hilfreich einfach nur einen Zufallswert direkt aus der Datenbank geliefert zu bekommen. Dieses kann man ganz einfach wie folgt realisieren.

MS-SQL-Server:
SELECT TOP 1 * FROM Testtabelle
ORDER BY NEWID();

SQLite:
SELECT * FROM Testtabelle ORDER BY RANDOM() LIMIT 1; 

Dienstag, 19. Juli 2011

Windows Mobile - .Net Compact Framework Exceptions anzeigen

Bei einem aktuellen Projekt arbeite ich an einer Anwendung für ein Windows CE 5.0 Gerät. Um genau zu sein handelt es sich um einen Scanner vom Typ Casio DT-X7.

Bei der Entwicklung habe ich festgestellt, dass meine Fehlerprotokolle (Logging der Exceptions in eine Textdatei) nicht korrekt geschrieben werden können. Und zwar wurde immer folgende Meldung protokolliert, egal welcher Fehler aufgetreten ist:

"An error message is available for this exception but cannot be displayed because these messages are optional and are not currently installed on this device. Please install ‘NETCFv35.Messages.EN.wm.cab’ for Windows Mobile 5.0 and above or  ‘NETCFv35.Messages.EN.cab’ for other platforms. Restart the application to see the message."

Folglich habe ich mich, ganz wie in der Meldung beschrieben, daran gemacht die angegeben CAB zu installieren. Hierzu habe ich die folgende Datei von meinem PC (Windows Mobile SDK muss installiert sein) auf das mobile Gerät kopiert:

C:\Programme\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE\Diagnostics\NETCFv35.Messages.EN.cab

Nach dem Kopieren habe ich die Datei auf dem mobilen Gerät gestartet und erfolgreich installiert.

Hier gilt es zu beachten, dass es im genannten Verzeichnis auch eine Datei "NETCFv35.Messages.EN.wm.cab" gibt. Diese Datei ist ausschließlich für Geräte mit Windows Mobile. Die Datei ohne ".wm" im Namen ist für alle weiteren Systeme wie z. B. Windows CE.

Verwendet man versehentlich die falsche Datei, so kommt eine Fehlermeldung vor der Installation wie z. B. folgende:

The file "NETCFv35.Messages.EN.wm.cab" is not a valid Windows CE Setup file.

In diesem Fall empfehle ich einfach noch einmal genau hinzuschauen und ggf. auch einmal das Bestriebssystem auf dem mobilen Gerät zu überprüfen. Manchmal hat man vielleicht doch etwas verwechselt oder übersehen.

Wurde aber alles korrekt installiert, so sollten auch die Fehlermeldungen wieder korrekt angezeigt/protokolliert werden.

Bei mir war dieses aber nicht der Fall. So musste ich weitersuchen.
Hierfür habe ich mir die kostenfreien Windows Mobile Power Toys von Microsoft installiert und mit dem MobileLogger geschaut, ob es noch irgendwelche Probleme gibt. Und ich bin direkt fündig geworden. Der Logger zeigt mir die Meldung:

"Failed to load [System.SR, Version=3.5.0.0, Culture=neutral, PublicKeyToken=969DB8053D3322AC]"

Das Problem hier ist, dass eine im CAB enthaltene Datei unter anderem Namen vorliegt, als sie eigentlich referenziert ist. Und zwar handelt es sich hierbei um die Datei "SYCCFA~1.001". Als Referenz wird der Name "System.SR" erwartet. Helfen kann man sich hier ganz einfach, in dem man die CAB-Datei entpackt, die Datei in "System.SR.dll" umbenennt und diese anschließend im sein Windows Mobile Projekt als Referenz einbindet.

Jetzt wurden sogar bei mir alle Fehlermeldungen korrekt ausgegeben.

Donnerstag, 14. Juli 2011

MonoTouch: UITextView mit zentriertem Inhalt bei der Bearbeitung

In einer IPhone-App hatte ich gerade das Problem, dass ich eine UITextView (Textbox) implementiert habe, die im Bearbeitungsmodus (nach Klick) immer den beinhalteten Text außerhalb des sichtbaren Bereichs verschoben hat. Das heißt, man musste jedes Mal scrollen um den Text zu sehen.

So sieht das ganze dann im Einsatz aus:

Dieses liegt daran, dass die UITextView standardmäßig einen unteren "Rahmen" von 32 Pixel einfügt. Da auch standardmäßig das Autoscrolling aktiv ist, wird immer die letzte Zeile fokussiert. Somit rutsch der eigentlich Inhalt/Text soweit nach oben, dass er nicht mehr sichtbar ist.

Abhilfe schafft hier die kleine Property "ContentInset".

Codebespiel:
UITextView textView = new UITextView(new RectangleF(10, 10, 280, 30));
textView.ContentInset = new UIEdgeInsets(0, 0, 0, 0);

Und so sieht das Ganze dann mit der gesetzten Property aus:

Freitag, 8. Juli 2011

SQLite BulkInsert-Alternative - Kleiner Code, große Wirkung


Heute bin ich auf ein Performance-Problem beim Füllen einer SQLite Datenbank gestoßen. Und zwar nutze ich für eine mobile Anwendung eine Datenbank, welche sich täglich komplett  inhaltlich verändern kann. Diese Datenbank wird dann per REST Webservice aus einem ASP.Net Web heruntergeladen.

Die Datenbank beinhaltet zwei Tabellen mit jeweils zehn Spalten. Da es bei SQLite kein Bulk-Insert wie z.B. beim SQL-Server gibt, habe ich zuerst versucht die ca. 40.000 Datensätze nacheinander ganz einfach per INSERT einzufügen. Dieses war mir aber deutlich zu langsam, so dass ich nach optimaleren Alternativen gesucht habe. Und ich bin auch recht schnell fündig geworden. Hierfür konnte ich sogar meine bestehende Programmierung fast komplett behalten. Ich musste lediglich einen kleinen Teil umstellen und um ein paar Zeilen Code erweitern.

Hier ist erst einmal zur Übersicht der Aufbau der ersten Tabelle.

CREATE TABLE Artikel(Artikelnummer VARCHAR(255) PRIMARY KEY ,EAN 
VARCHAR(255),Artikelbezeichnung1 VARCHAR(255),Artikelbezeichnung2 
VARCHAR(255),Hersteller VARCHAR(255),EmpfVK FLOAT,Verfuegbarkeit INTEGER, 
Gewicht FLOAT, Status_NichtVerfuegbar BOOLEAN,Artikelinfo 
TEXT);


Das Befüllen der Tabelle sieht dann in meine Programmierung wie folgt aus.


   1:  
   2: SQLiteConnection connection = new 
   3: SQLiteConnection();
   4:      
   5: SQLiteCommand command = new 
   6: SQLiteCommand(connection);
   7: command.CommandText = "INSERT INTO Artikel 
   8: VALUES 
   9: (@Artikelnummer,@EAN,@Artikelbezeichnung1,@Artikelbezeichnung2,@Hersteller,@EmpfVK,@Verfuegbarkeit,@Gewicht,@Status_NichtVerfuegbar,@Artikelinfo);";
  10: command.Prepare();
  11:  
  12:  
  13: SQLiteTransaction tr = connection.BeginTransaction();
  14: command.Transaction = tr;
  15:  
  16:  
  17: for (int 
  18: i = 0; i < listArtikel.Count; i++)
  19: {
  20:   command.Parameters.Add(new SQLiteParameter("@Artikelnummer", listArtikel[i].Artikelnummer));
  21:   command.Parameters.Add(new SQLiteParameter("@EAN", 
  22: listArtikel[i].EAN));
  23:   command.Parameters.Add(new SQLiteParameter("@Artikelbezeichnung1", 
  24: listArtikel[i].Artikelbezeichnung1));
  25:   command.Parameters.Add(new SQLiteParameter("@Artikelbezeichnung2", 
  26: listArtikel[i].Artikelbezeichnung2));
  27:   command.Parameters.Add(new SQLiteParameter("@Hersteller", 
  28: listArtikel[i].Hersteller));
  29:   command.Parameters.Add(new SQLiteParameter("@EmpfVK", 
  30: listArtikel[i].EmpfVK));
  31:   command.Parameters.Add(new SQLiteParameter("@Verfuegbarkeit", listArtikel[i].Verfuegbarkeit));
  32:   command.Parameters.Add(new SQLiteParameter("@Gewicht", 
  33: listArtikel[i].Gewicht));
  34:   command.Parameters.Add(new SQLiteParameter("@Status_NichtVerfuegbar", 
  35: listArtikel[i].Status_NichtVerfuegbar));
  36:   command.Parameters.Add(new SQLiteParameter("@Artikelinfo", 
  37: listArtikel[i].Artikelinfo));
  38:  
  39:  
  40:   command.ExecuteNonQuery();
  41:  
  42:  
  43:   command.Parameters.Clear();
  44: }
  45:  
  46:  
  47: tr.Commit();
  48: command.Dispose();

Das Wichtigste an dieser Programmierung ist, dass sich die Parameter-Zuweisung sowie die Ausführung (ExecuteNonQuery) innerhalb der gestarteten Transaktion liegt. Außerdem sollte das eigentliche SQL-Statement (Command.Text) außerhalb der Schleife und nicht bei jedem Durchlauf zugewiesen werden.

Ein weiterer wichtiger Punkt ist das Aufbereiten des SQL-Statements mit command.Prepare().

Mir hat die Implementierung der Transaktion eine Zeitersparnis von fast 90% gebracht. Ich denke das ist ein sehr erstaunliches Ergebnis.

Samstag, 2. Juli 2011

Base64-Strings encodieren und decodieren

Gerade wenn man Web-Applikationen entwickelt und mit Datenübertragungen zu tun hat, wird man regelmäßig mit sogenannten Base64-Strings konfrontiert. Wenn man dieses zum ersten Mal hört, fragt man sich wahrscheinlich, was das eigentlich ist.
Dabei ist das alles eigentlich ganz einfach. Base64 ist eine Kodierung für 8-Bit-Binärdaten wie zum Beispiel Bilder, PDF-Dokumente oder Zip-Archive. Bei einer Base64-Kodierung werden die Binärdaten zum Beispiel eines Bildes in einen lesbaren ACII-String umgewandelt. Daher ist auch oft die Rede von einem Base64-String. Erkennen kann man eine solche Zeichenkette daran, dass keine Sonderzeichen außer "+", "/" und "=" vorhanden sind und der String immer mit einem "="-Zeichen endet.

Setzt man das ganze nun in der Programmierung (C# / .Net) um, könnte es wie folgt aussehen.

Daten encodieren / String in Base64-String umwandeln

public string base64Encode(string dataToEncode)
{
     // Übergebenen String in ein ByteArray umwandeln
     byte[] bytesToEncode = System.Text.Encoding.UTF8.GetBytes(dataToEncode);

     // Erstelltes ByteArray in einen Base64 kodierten String umwandeln und zurückgeben
     return Convert.ToBase64String(bytesToEncode);
}  

Daten decodieren / Base64-String in String umwandeln

public string base64Decode(string dataToDecode)
{
     // Ein Objekt der Klasse ASCIIEncoding instanziieren
     System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();

     // Übergebenen String in ein ByteArray umwandeln
     byte[] bytesToDecode = Convert.FromBase64String(dataToDecode);

     // Erstelltes ByteArray aus dem Base64-String in einen decodierten (nicht kodierten) String umwandeln und zurückgeben
     return encoding.GetString(bytesToDecode);
}

Donnerstag, 30. Juni 2011

Microsoft SQL-Server Verbindungsserver einrichten

Mit folgendem, simplen SQL-Statement würde man Daten der Tabelle "Maschinen" aus der Datenbank "FlorianTestDB" von einem Server "Testserver2" auf einen anderen Server "Testserver1" in die gleichnamige Datenbank/Tabelle kopieren.

INSERT INTO [Testserver1].[FlorianTestDB].[dbo].[Maschinen]
SELECT * FROM [Testserver2].[FlorianTestDB].[dbo].[Maschinen]
GO

Voraussetzung für eine erfolgreiche Übertragung ist, dass der Zielserver als sogenannter Verbindungsserver auf dem Quellserver eingerichtet ist. Ist dieses nicht der Fall, so kommt folgende Meldung.

Meldung 7202, Ebene 11, Status 2, Zeile 1
Server 'Testserver1' konnte in 'sys.servers' nicht gefunden werden. Stellen Sie sicher, dass der richtige Servername angegeben wurde. Führen Sie ggf. die gespeicherte Prozedur 'sp_addlinkedserver' aus, um den Server in 'sys.servers' hinzuzufügen.

Abhilfe schafft man, indem man den Verbindungsserver auf einfache Art und Weise  anlegt. Hierzu muss man eine Verbindung mit dem Quellserver herstellen und folgenden Befehl ausführen, um den Zielserver als Verbindungsserver einzurichten.

EXEC sp_addlinkedserver 'Testserver1'
GO

Als Ergebnis sollte folgendes zurückkommen.

Befehl(e) wurde(n) erfolgreich abgeschlossen.

Führt man das SQL-Statement zum Kopieren der Daten nun erneut aus, so sollte es erfolgreich ausgeführt werden.

Eine kleine Einschränkung hierbei gibt es jedoch. Fügt man den Verbindungsserver wie oben beschrieben hinzu, so ist es notwendig, dass auf beiden Servern der aktuell verwendete Benutzer identisch eingerichtet ist.

Möchte man dieses nicht, benutzt unterschiedliche Passwörter oder verschiedene Benutzer, so ist es am einfachsten den Verbindungsserver über das SQL-Server-Management-Studio anzulegen.

Diese Vorgehensweise geht für die SQL-Server-Versionen 2000, 2005 und 2008

Dienstag, 28. Juni 2011

Dateidownload via REST-Webservice

REST ist ein Akronym für Representational State Transfer. Einfach gesagt steht REST für eine Art der Datenübertragung per HTTP.  Unterhalb von REST gibt es noch eine weitere Unterscheidung je nach Befehlstyp. Hier gibt es folgende Möglichkeiten:

- GET (Download von Dateien)
- POST (Upload von Dateien)
- PUT (Upload von Dateien)
- DELETE (Löschen von Dateien)

Im folgenden Beispiel zeige ich, wie man einen einfachen Datei-Download anhand eines REST-Webservices (per GET) erstellen kann.

Bei "context" handelt es sich um den aktuellen HttpContext.

// Prüfen der Http-Übertragungsmethode
if(context.Request.HttpMethod = "GET")
{
    // FileInfo-Objekt für die Datei erstellen, die heruntergeladen werden soll
    FileInfo requestFile = new FileInfo("C:\\Testdatei.txt");

    // Anhand der gerade ermittelten Datei ein ByteArray für eine Datenübertragung erstellen
    byte[] fileBytes = File.ReadAllBytes(requestFile.FullName);

    // Aktuellen Inhalt des HttpContextes leeren
    context.Response.Clear();

    // Aktuelle Headerinformationen des HttpContextes leeren
    context.Response.ClearHeaders();

    // Angabe des Types der zu übertragenden Datei 
    context.Response.ContentType = "text/plain";

    // Neue Headerinformationen zum HttpContext hinzufügen
    context.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + requestFile.Name + "\"");
    context.Response.AddHeader("Content-Length", requestFile.Length.ToString());
    
    // MD5-Hash für aktuelle Datei erstellen um nach dem Download die Vollständigkeit zu prüfen
    // Info: FileHelper ist eine eigene Hilfs-Klasse zum erstellen des MD5-Hash (siehe ältere Blogposts)
    context.Response.AddHeader("Content-MD5", StringHelper.Base64Encode(FileHelper.GetMD5Hash(requestFile.FullName)));
    
    // Die Datei/ByteArray ausgeben bzw. zum Download anbieten
    context.Response.OutputStream.Write(fileBytes, 0, fileBytes.Length);
    
    // HttpResponse wieder freigeben
    context.Response.Flush();

    // HttpResponse beenden
    context.Response.End();
}

Montag, 27. Juni 2011

MD5-Hash einer Datei erstellen

Wenn man mit Dateien arbeitet speziell im Bereich Download/Upload, muss man immer wieder Dateien auf Vollständigkeit prüfen. Dieses kann man am besten über einen MD5-Hash machen.
Erstellt man einen MD5-Hash der Ursprungsdatei kann man diesen mit dem der neu erstellten Datei vergleichen um zu prüfen, ob die Dateien übereinstimmen. Ist das nicht der Fall, so ist beim Download/Upload etwas schief gelaufen.

Einen MD5-Hash kann man ganz einfach wie folgt erstellen.

// Gibt einen MD5-Hash-String für eine Datei zurück
public static string GetMd5HashString(string filePath)
{
     // Datei in neues FileStream-Objekt einlesen
     FileStream fileStream = new FileStream(filePath, FileMode.Open);

     // Neues Objekt für MD5-Kryptographi-Provider erstellen
     MD5 md5 = new MD5CryptoServiceProvider();

     // ByteArray mit MD5-Hash der eingelesenen Datei erstellen
     byte[] fileHash = md5.ComputeHash(fileStream);

     // FileStream mit eingelesener Datei wieder schließen
     fileStream.Close();

     // StringBuilder-Objekt erstellen um anschließend den MD5-Hash als String zu speichern
     StringBuilder sb = new StringBuilder();

     // MD5-Hash (ByteArray) byteweise verarbeiten und an StringBuilder anhängen
     for (int i = 0; i < fileHash.Length; i++)
     {
          sb.Append(fileHash[i].ToString("x2"));
     }

     // MD5-Hash als String ausgeben
     return sb.ToString();
}

Freitag, 24. Juni 2011

Installierte Versionen des .Net-Framework ermitteln unter Windows Mobile

Heute hatte ich das Problem, dass ich eine kleine Testanwendung schreiben wollte die auf einem Windows Mobile und einem Windows CE Gerät laufen sollte. Einzige Voraussetzung war, dass kein neues .Net Framework bzw. Compact Framework installiert werden darf.

Da es sich bei dem einen Gerät um das Betriebssystem Windows CE 5.0 handelt, kommen für die Entwicklung erst einmal 2 Framework-Versionen in Frage. Und zwar hat die Version 5.0 standardmäßig das .Net-Framework 1.0 installiert. Handelt es sich jedoch um die Version 5.0 mit installiertem Service Pack 2, so ist auch das .Net-Framework 2.0 eingerichtet.

Wie bekommt man nur einfach raus, welches das aktuell höchste, vorhandene .Net-Framework ist.
Hierzu gibt es eigentlich zwei ganz einfache Methoden.

1. Im Windows-Verzeichnis befindet sich eine Datei mit dem Namen "cgacutil.exe". Wenn man diese einfach ausführt, bekommt man alle installierten .Net-Frameworks, sortiert von alt nach neu, aufgelistet.
Der letzte Eintrag ist also die höchste installierte Version.

2. Sollte die unter Punkt 1 beschriebene Datei aus irgendwelchen Gründen nicht aufrufbar sein, so kann man sich auch einen Registry-Editor zur Hilfe ziehen. Diesen installiert man auf dem PC und greift von dort aus auf das angeschlossene mobile Gerät zu.
Aus dem Editor geht man dann in der Registry unter folgenden Eintrag:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP
Hier werden alle installierten Versionen des .Net-Frameworks in Unterverzeichnissen aufgelistet.

Mittwoch, 22. Juni 2011

Zugriff aus .Net auf SQLite Datenbanken

In meinem letzten Beitrag habe ich mich ja mit einem universellen Datenbank-Browser für Mac OS und Windows beschäftigt. Dieses war mir auch sehr wichtig, da man so recht schnell Datenbanken erstellen, mit ersten Testdaten füllen und später die richtigen Daten gut prüfen kann.

Jetzt möchte ich aber den eigentlich interessanteren Teil ansprechen. Den Datenzugriff aus .Net auf eine SQLite-Datenbank.

In folgendem Beispiel möchte ich zeigen, wie man per C#-Code eine SQLite-Datenbank erstellt, eine Tabelle anlegt und diese mit Daten befüllt.


// Datenbanknamen angeben
string dataBaseName = "Maschinen.db";

// Connection-Objekt instanziieren
SQLiteConnection connection = new SQLiteConnection();

// Datenbankdatei erstellen (inkl. Standarddatenbank "main")
SQLiteConnection.CreateFile(dataBaseName);

// Connection-String für die Verbindung erstellen
connection.ConnectionString = "Data Source=" + dataBaseName;

// Verbindung zur Datenbank erstellen
connection.Open();

// Command-Objekt instanziieren um SQL-Statements auszuführen
SQLiteCommand command = new SQLiteCommand(connection);

// SQL-Statement ohne Parameter erstellen und ausführen
command.CommandText = "CREATE TABLE Maschinen(Id INTEGER PRIMARY KEY, Name VARCHAR(255), Typ VARCHAR(255));";
command.ExecuteNonQuery();

// SQL-Statement mit Parametern erstellen
command.CommandText = "INSERT INTO Maschinen VALUES (@Id, @Name, @Typ);";

// Command-Objekt mit Parametern füllen
command.Parameters.Add(new SQLiteParameter("@Id", 1));
command.Parameters.Add(new SQLiteParameter("@Name", "Maschine1"));
command.Parameters.Add(new SQLiteParameter("@Typ", "Typ1"));

// SQL-Statement mit Parametern ausführen
command.ExecuteNonQuery();

// Parameter aus Command-Objekt wieder entfernen
command.Parameters.Clear();

// Command-Objekt wieder freigeben
command.Dispose();

// Verbindung zur Datenbank schliessen
connection.Close();

Dienstag, 21. Juni 2011

SQLite Datenbank-Browser für Mac und Windows

Da ich momentan viel parallel mit Windows und Mac OS arbeite und auch bei kleineren Projekten oft SQLite-Datenbanken verwende, habe ich einen Datenbank-Browser gesucht, der unter beiden Plattformen läuft.

Bei der Suche bin ich über interessante Clients gestolpert, die auch wirklich gut waren. Viele sind aber entweder für Mac OS oder für Windows gewesen. Letztendlich bin ich bei einen Open Source Tool hängen geblieben. Dieses trägt den Namen "SQLite Database Browser" und ist zu finden unter folgendem Link.
http://sqlitebrowser.sourceforge.net/

SQLite Database Browser unter Mac OS

Dieses Tool ist zwar grafisch nicht sehr anspruchsvoll, aber das muss ein Datenbank-Browser meiner Meinung nach auch nicht sein. Man kann mit ihm alle Grundfunktionalitäten abdecken wie zum Beispiel:
- Neue Datenbanken erstellen
- Bestehende Datenbanken einlesen (Daten sowie Struktur anzeigen)
- Strukturen verändern (Tabellen und Indizes erstellen, ändern und löschen)
- SQL-Abfragen ausführen

Dienstag, 14. Juni 2011

Versionierung in .Net - Assembly Version setzen und auslesen

Wie ist eine Versionsnummer aufgebaut?
Eine Versionsnummer sieht z. B. so aus: 1.6.34.55
Diese Werte stehen standardmäßig für folgende Werte: Major Version, Minor Version, Build Number, Revision.

Wie kann man einfach und schnell eine .Net-Applikation mit einer Versionsnummer versehen?

Dieses kann man ganz einfach realisieren indem man die AssemblyInfo.cs anpasst. Die Datei enthält standardmäßig folgende Codezeile:
[assembly: AssemblyVersion("1.0.0.0")] 

Hier könnte man nun manuell eine neue Versionsnummer eintragen wie zum Beispiel folgende:
[assembly: AssemblyVersion("1.1.3.7")]

Da dieses aber aus der Erfahrung heraus in den meisten Fällen regelmäßig vergessen wird, wäre es doch sinnvoll, wenn sich die Versionsnummer automatisch erhöht wird.

Um dieses einfach, schnell und ohne viel Aufwand realisieren zu können, kann man die Zeile wie folgt anpassen.
[assembly: AssemblyVersion("1.0.*")]

Somit werden die letzten beiden Werte (Build Number und Revision) automatisch inkrementell erhöht.

Das Auslesen der aktuellen Versionsnummer ist genauso einfach. Dieses funktioniert mit folgender Zeile Code:
System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()