13 December 2005

VB6 Unit Testing: Wir brauchen doch keine Datenbank

Mit besten Dank an Sebastian von Däniken

Weg mit der Datenbank!

Wer clever Unit Tests schreibt, testet nicht gegen eine richtige Datenbank, sondern versucht diese zu simulieren. Test gegen externe Systeme wie Datenbanken, Netzwerke, etc. sollten generell vermieden werden, da man den Ausgang der Test nicht von deren Verfügbarkeit abhängig machen will.

Datenbankabfrage als XML Datei speichern


In MS ActiveX Data Objects (ADO) lasst sich mit der Klasse ADODB.Recordset eine Abfrage in eine Textdatei (XML oder Microsoft Advanced Data TableGram). Das nachfolgende Beispiel verwendet die XML Variante als Speichermedium. Bei grossem Datenumfang ist die MS ADTG Variante schneller sein, da es sich um ein binäres Format handelt.


Dim conn As ADODB.Connection
Dim rs As ADODB.Recordset

Set conn = New ADODB.Connection

conn.Open "DSN=myDNS;", "meinUser", "MeinPasswort"

Set rs = conn.Execute("SELECT * FROM Kunde WHERE Vorname = 'Silvio';")

rs.Save "c:\myADO.xml", adPersistXML

conn.Close

Set rs = Nothing
Set conn = Nothing

12 September 2005

7 September 2005

Zeichenketten mit Oracle verknüpfen

Um mit SQL (unter Oracle) Zeichenketten zu verknüpfen benötigt man den Operator || (2 Pipes). Das Ganze kann bspw. folgendermassen ausschauen.

SELECT FILENAME || '.txt' FROM SCHEMANAME.TABLENAME;

----------------
FILENAME
----------------
Readme.txt
HOWTO.doc.txt
----------------
2 rows returned

17 June 2005

Listview und Visual Basic 6

Controls unter Visual Basic 6 - speziell das Listview Control - sind nun wirklich sehr primitiv was die Zugriffsmethoden angeht. Es ist bspw. nicht möglich einen Full Row Select (beim Mausklick ganze Zeile markieren) standardmässig via die Control Properties einzustellen.

Glücklicherweise lässt sich dies via der Win API "nachrüsten", so dass die Listview doch noch anständig daher kommt. Das nachfolgende Listing zeigt wie es geht.


Option Explicit

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal Msg As Long, _
ByVal wParam As Long, _
lParam As Any) As Long

Private Const LVM_FIRST = &H1000
Private Const LVM_SETEXTENDEDLISTVIEWSTYLE = (LVM_FIRST + 54)
Private Const LVM_GETEXTENDEDLISTVIEWSTYLE = (LVM_FIRST + 55)

Public Const LVS_EX_FULLROWSELECT = &H20

Private Sub Check1_Click()

Dim state As Long

state = Check1.Value = 1
Call SendMessage(ListView1.hwnd, _
LVM_SETEXTENDEDLISTVIEWSTYLE, _
LVS_EX_FULLROWSELECT, ByVal state)

End Sub

23 May 2005

Baumstrukturen mit Oracle abbilden

Quelle: Lorenz Graf, COR Infexpert AG

Ausgangslage

In der Tabelle EXAMPLETREE wird ein Baum abgebildet. Via der NODE_ID lässt sich die PARENT_ID oder mittels dieser wiederum die Childnodes des Parents ermitteln.

CREATE TABLE EXAMPLETREE
(
NODE_ID NUMBER(10) NOT NULL,
PARENT_ID NUMBER(10) NOT NULL
);

Um nun die Struktur ausgehend einer Knoten ID abwärts zu ermitteln, kann man entweder im Programmcode einen Algorithmus implementieren, welcher die Children IDs rekursiv ermittelt oder man verwendet die Werkzeuge von Oracle (START WITH / CONNECT BY) und kapselt somit diese Logik in der Datenbank.

Die nachfolgende SELECT Abfrage ermittelt alle Children IDs unterhalb einer NODE_ID und ordnet diese absteigend nach Strukturlevel.


SELECT NODE_ID,LEVEL
FROM FIN_P430_CORP_NODE_CHILDREN
START WITH PARENT_ID = 6000
CONNECT BY PRIOR NODE_ID = PARENT_ID
ORDER BY LEVEL DESC;

27 April 2005

Wie schreibe ich unleserlichen Code?

Unter diesem Link findet sich eine unterhaltsame und ernstgemeinte Abhandlung wie man einfach und konsequent unleserlichen Code produziert.

Mein absoluter Favorit:
Wenn Dein Boss der Meinung ist, dass seine 20jährige FORTRAN-Erfahrung ein exzellenter Leitfaden zur objektorientieren Programmierung darstellt, folge stur seinen Empfehlungen. Du wirst sehen, dass Dein Boss sein Vertrauen in Dich setzt. Und das kann Deiner Kariere nützen. Und Du wirst jede Menge neuer Techniken der Code-Verschleierung kennenlernen.


Viel Spass beim Lesen :)

18 April 2005

Rot - Grün - Refaktorisieren

Wieder einmal, während einem nächtlichen Ausflug im Internet, bin ich auf ein interessantes Modell zum Thema testgetriebene Entwicklung gestossen. Diese Entwicklungsmethodik fordert Tests für jedes Stück Funktionalität im Programmcode. Ungetesteter Code ist grundsätzlich inexistent.

Um mit dieser Entwicklungsmethodik ebenfalls schnell vom Fleck zu kommen gibt es die sogenannte "Rot - Grün - Refaktorisieren" Regel. Hier zu bin ich auf eine interessante Illustration zu dem Vorgehen gestossen.

16 April 2005

Aufwärmphase mit Hibernate

Default Konstruktoren machen es aus

Hibernate arbeitet mit sogenannten POJOs (Plain Old Java Objects) und zu diesen Objekten muss sinngemäss stets ein Default Konstruktor zur Verfügung stehen. Ansonsten reagiert Hibernate nicht so erfreut auf die Proxyklasse.

Data Description Language aus Mapping Dateien erstellen

Mit Hibernate können Applikationen datenbankunabhängig entwickelt werden. Dies ist vor allem sehr hilfreich, wenn man keine Administratorenrechte auf der Kundendatenbank hat oder mehrere Entwickler im Minutentakt ihre Testskripts gegen eine Datenbank ausführen und sich einander somit stören, da die Testresultate verfälscht werden.

Die freie Java Datenbank Hypersonic und Hibernate bieten sich hier als kleine aber mächtige Werkzeuge an, um dieses alltägliche Problem zu beheben.

Grundlage für das Beispiel bildet das folgende Hibernate Mapping File.
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd" >

<hibernate-mapping package="ch.silvio.hibernate">
<class name="FileNetUser" table="tbl_filenet_user">
<id
column="fn_id"
name="Id"
type="integer"
>
<generator class="native" />
</id>
<property
column="fn_usr"
length="30"
name="Username"
not-null="true"
type="string"
/>
<property
column="fn_pwd"
length="30"
name="Password"
not-null="false"
type="string"
/>
</class>
</hibernate-mapping>

Diese einfache Enität beinhaltet als Attribute einen numerischen Schlüssel und jeweils eine Zeichenkette für Benutzername und Passwort. Mittels einem kleinen Java Programm und der Hibernate API lässt sich aus dieser Mapping Datei sowohl eine Java Klasse als auch ein SQL Skript (DDL) für eine von Hibernate unterstützten Datenbanken erstellen.

public class Hypersonic
{
//....
static
{
Configuration config = new Configuration();
config.setProperty("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
config.setProperty("hibernate.connection.driver_class","org.hsqldb.jdbcDriver");
config.setProperty("hibernate.connection.url", "jdbc:hsqldb:mem:test");
config.setProperty("hibernate.connection.username", "sa");
config.setProperty("hibernate.connection.password", "");
config.setProperty("hibernate.connection.pool_size", "1");
config.setProperty("hibernate.connection.autocommit", "true");
config.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.HashtableCacheProvider");
config.setProperty("hibernate.hbm2ddl.auto", "create-drop");
config.setProperty("hibernate.show_sql", "true");


config.addClass(FileNetUser.class);
factory = config.buildSessionFactory();
}
//...
}

Im vorherigen Codeausschnitt wird eine Hibernate Configuration zur Laufzeit erstellt. Dieses Objekt wird in einer produktiven Applikation meisten durch die XML Datei hibernate.cfg.xml konfiguriert. Für das kleine Beispiel genügt es uns, wenn die Configuration im Quellcode erstellt wird.
Nun weiss Hibernate, dass wir uns auf eine Hybersonic Datenbank verbinden wollen.

public static void main(String[] args)
{
SchemaExport exporter = new SchemaExport(config);
exporter.setOutputFile("cone.sql");
exporter.setDelimiter(";"); // Setze ein Semikolon ans Ende des SQL Statments
exporter.create(true, false); // Skript nicht mit der DB aktualisieren aber auf der Konsole ausgeben.
}

In der Hibernate API existiert eine Klasse namens SchemaExport mit welcher man sehr einfach aus einer Hibernate Mapping Datei ein SQL Skript erstellen kann bzw. das Skript direkt via der konfigurierten JDBC Verbindung von Hibernate auf der Datenbank ausführen kann. Diese Klasse bzw. eine Erweiterung davon SchemaExportTask lässt sich auch als Task in Ant einbinden. Nachdem die Methode main ausgeführt wurde, kann man sowohl in der Datei cone.sql als auch auf der Console (stdout) das nachfolgende SQL Skript sehen. Dieses Skript ist im HSQLDB SQL Dialect erstellt worden und kann daher problemlos auf der Hybersonic Datenbank ausgeführt werden.

drop table tbl_filenet_user if exists;
create table tbl_filenet_user (
fn_id integer generated by default as identity (start with 1),
fn_usr varchar(30) not null,
fn_pwd varchar(30),
primary key (fn_id)
);