Zum Hauptinhalt springen
Version: Preview

Daten aus Datenbank lesen

Fügen Sie zur Nutzung der Datenbank Funktionen immer das using Statement

using Mum.Geo.DataAccess;

in den Kopf Ihrer Klasse ein.

Warnung

Beachten Sie das wenn Sie Datenabfragen durchführen und das Ergebnis sehr viele Datensätze zurückliefert, das dies zu Speicherüberlauf (und damit Abstürzen) oder zum Stillstand von MapEdit führen kann da alle Datensätze bei diesem Methoden vom Server auf den Client geladen werden. Bedenken Sie also immer was Sie tun und fragen Sie nicht alle Datensätze einer Tabelle ab sondern nur die Datensätze die Sie wirklich benötigen.

Bitte beachten

Binden Sie keine Datenbank Provider DLLs wie npgsql.dll, Oracle.DataAccess.Client.dll, system.datasqlite.dll etc ein. Diese werden für MapEdit nicht benötigt. MapEdit ist eine Client - Server Software. Ihr Plugin Code läuft auf dem Client. Alle Datenbank Zugriffe geschehen über die MapEdit API welche dann die Daten vom Server abfragt.

Feature Object

Die Klasse "Feature" sollte immer dann genutzt werden wenn sie einen Datensatz lesen und spätere auch wieder zurück in die Datenbank schreiben wollen.

Das Feature holt immer alle Spalteninformationen des Datensatzes von der Datenbank.

Einzelnen Datensatz/Feature abfragen

Wenn die FID bekannt ist können Sie ein Feature folgendermaßen von der Datenbank abfragen.

Connection cn = this.Connection;

//Der erste Parameter ist der Tabellenname
//Der zweite Parameter ist der Wert der Primaerschluessel Spalte
//Im normalfall die FID oder ID des Datensatzes.

Feature feature = cn.ReadFeature("BAUM", "177");

long fid = feature.GetInt64Ex("FID");
string name = feature.GetStringEx("NAME");
double area = feature.GetDoubleEx("AREA");
DateTime date = feature.GetDateEx("DATE_CREATED")

//Check if the Column has a value
if (!feature.IsDBNull("COLORNAME"))
{
string color = feature.GetStringEx("COLORNAME");
}

Mehrere Datensätze/Features mittels Filter anfragen

Sie können mehrere Feature auch mittels eines Filters lesen. der Filter entspricht einer SQL "Where" Bedingung.

Connection cn = this.Connection;

//Der erste Parameter ist der Tabellenname
//Der zweite Parameter der Filter (die SQL Where Bedingung)

List<Feature> features = cn.ReadFeatures("BAUM", "area<1000");
foreach(Feature feature in features)
{
long fid = feature.GetInt64Ex("FID");
string name = feature.GetStringEx("NAME");
double area = feature.GetDoubleEx("AREA");
}

feature.Key liefert jeweils den Wert der Primärschlüsselspalte als Textwert zurück.
Im Normalfall ist das die Spalte FID, oder ID bei Kennungslisten.

string fidString = feature.Key;

feature.KeyID liefert jeweils den Wert der Primärschlüsselspalte als long Wert zurück.

long fid = feature.KeyID;

Abfrage via SQL

Im Gegensatz zur Klasse "Feature" kann hier explizit angegeben werden welche Spalten von der Datenbank abgerufen werden sollen.

Hier können beliebige SQLs angegeben werden, d.h. es können im Gegensatz zur Klasse "FEature" auch mehrere Tabellen kombiniert werden.

Diese vorgehen ist in Fällen wo nur Daten gelesen werden das Bessere da bei diesem vorgehen die Menge an Daten kleiner ist. Dadurch ist die Abfrage schneller und es müssen weniger Daten vom Server an den Client übertragen werden.

Das folgende Beispiel liest den Spalten Wert eines einzelnen Datensatzes

Connection cn = this.Connection;
string name = cn.SqlQueryScalarString("select NAME from BAUM where FID=17");

Wenn Sie einen anderen Datentyp brauchen verwenden Sie

cn.SqlQueryScalarDouble
cn.SqlQueryScalarInt
cn.SqlQueryScalarLong
usw.

Wenn Sie auf Fehler prüfen wollen:

Connection cn = this.Connection;
try
{
string name = cn.SqlQueryScalarString("select NAME from BAUM where FID=17", SqlExceptionBehavior.ThrowException);
}
catch(System.Exception ex)
{
XMsgBox.Show(ex.Message);
}

Das folgende Beispiel liest alle Spalten Werte der Spalte "name" aller Datensätze des SQLs und gibt eine Liste aller Namen zurück

Connection cn = this.Connection;
List<string> alleNamen = this.Connection.SqlQueryListString("select name from person where age>18");

Das folgende Beispiel liest Datensätze mittels eines SQLs.

Connection cn = this.Connection;

SqlQuery reader = new SqlQuery(cn);
reader.Query("select FID,NAME from BAUM where baumtyp=9");
while (reader.ReadNext())
{
long fid = reader.GetInt64Ex("FID");
string name = reader.GetStringEx("NAME");
}
reader.Close();

Mittels "reader.Succeeded" können Sie prüfen ob die Abfrage erfolgreich war und mittels "reader.ExceptionMessage" kann die Fehlermeldung gelesen werden.

SqlQuery reader = new SqlQuery(this.Connection);
reader.Query("select FID,NAME from BAUM where baumtyp=9");
if (!reader.Succeeded )
{
string err = reader.ExceptionMessage;
}

Werte von Stored Procedures lesen (Gespeicherte Prozeduren)

Damit eine gespeicherte Prozedur in MapEdit verwendet werden kann, muss sie als SELECT aufrufbar sein und ihr Ergebnis als Datensatz (Spalten) zurückliefern. Das Ergebnis wird anschließend mit der Klasse SqlQuery ausgelesen.

Ob ein direkter Aufruf möglich ist, hängt vom Datenbanksystem ab.

PostgreSQL

In PostgreSQL ist eine Funktion mit OUT-Parametern direkt selektierbar. Sie kann ohne weitere Vorbereitung verwendet werden:

Connection cn = this.Connection;

SqlQuery q = new SqlQuery(cn);
q.AddParameter("fid", DataType.DbInt64, fid);
q.Query("SELECT str, hnr FROM get_addressbyfid(:fid)");

if (q.Succeeded && q.ReadNext())
{
string str = q.GetStringEx("str");
string hnr = q.GetStringEx("hnr");
// ... weiterverarbeiten
}
q.Close();

Oracle

In Oracle kann eine Prozedur mit OUT-Parametern nicht in einem SELECT verwendet werden. Hierfür muss einmalig eine Funktion in der Datenbank angelegt, welche die vorhandene Prozedur aufruft und deren Ergebnis als Datensatz zurückgibt. Die ursprüngliche Prozedur bleibt dabei unverändert.

Variante A – Pipelined Table Function (ein Aufruf, alle Werte):

CREATE OR REPLACE TYPE address_t  AS OBJECT (str VARCHAR2(4000), hnr VARCHAR2(4000));
CREATE OR REPLACE TYPE address_tab AS TABLE OF address_t;

CREATE OR REPLACE FUNCTION get_address_fn(p_fid IN NUMBER)
RETURN address_tab PIPELINED
IS
v_str VARCHAR2(4000);
v_hnr VARCHAR2(4000);
BEGIN
get_addressbyfid(p_fid, v_str, v_hnr);
PIPE ROW(address_t(v_str, v_hnr));
RETURN;
END;

Aufruf im Script (nur die SQL-Zeile unterscheidet sich vom PostgreSQL-Beispiel):

q.Query("SELECT str, hnr FROM TABLE(get_address_fn(:fid))");

Variante B – zwei skalare Funktionen (einfacher, aber zwei Aufrufe):

Alternativ können zwei skalare Funktionen angelegt werden. Diese Variante kommt ohne Objekt-Typen aus, ruft die Prozedur jedoch zweimal auf.

CREATE OR REPLACE FUNCTION get_address_str(p_fid IN NUMBER) RETURN VARCHAR2 IS
v_str VARCHAR2(4000);
v_hnr VARCHAR2(4000);
BEGIN
get_addressbyfid(p_fid, v_str, v_hnr);
RETURN v_str;
END;
-- analog: get_address_hnr für v_hnr
string str = cn.SqlQueryScalarString("SELECT get_address_str(:fid) FROM dual");
string hnr = cn.SqlQueryScalarString("SELECT get_address_hnr(:fid) FROM dual");

Informationen zum lesen von Spaltenwerten

Die folgenden Informationen gelten für die Klassen Feature und SqlQuery gleichermassen.

Beachten Sie das Spaltenwerte leer (NULL) sein können.

Mit der Funktion feature.IsDBNull("spaltenname") kann geprüft werden ob der Spaltenwert NULL (leer) ist.

Beispiel:

string treeType = "";
if (!feature.IsDBNull("TREE_TYPE"))
{
treeType = feature.GetString("TREE_TYPE");
}

Sie können auch einen Wert vorgeben der zurück gegeben werden soll wenn die Spalte NULL ist.

Der erste Parameter ist der Name der Spalte Der zweite Parameter ist der Wert der zurück geliefert werden soll wenn die Spalte NULL ist.

Das folgende Beispiel liest den wert der Spalte NAME. Enthält die Spalte NAME keinen Wert (NULL) dann wird als Wert "Eiche" zurück gegeben.

string name = feature.GetString("NAME", "Eiche");

Dies steht bei allen DatenTypen Funktionen zur Verfügung. also auch bei GetInt32, GetBoolean usw.

Funktionen die mit "Ex" enden liefern wenn der Spaltenwert NULL ist jeweils einen fixen Vorgabewert zurück.

Hier eine Übersicht der Funktionen für verschiedenen Datentypen und was diese im Fall zurück wenn der Spaltenwert NULL ist.

FunktionRückgabewert
wenn NULL
GetStringEx"" (leerer String)
GetInt32Ex0
GetInt64Ex0
GetDoubleEx0.0
GetDateEx1/1/1900
GetDateTimeEx1/1/1900
GetBooleanExfalse

Int32 entspricht dem Datentyp integer
Int64 entspricht dem Datentyp long

Diese Namensgebung wurde so von Microsoft übernommen.
Diese verwenden diese so in ihren Frameworks wie z.B. ADO.NET.
Der Datentyp int ist das gleiche wie Int32.
Der Datentyp long ist das gleiche wie Int64.

Spezial Fall "GetBooleanEx" (Ja/Nein Werte)

Die meisten Datenbanken unterstützen keinen Datentyp Boolean. Um dieses Problem zu umgehen speichert MapEdit Boolean werte in der Datenbank als NUMBER(1) ab.

Die Funktion GetBoolean/GetBooleanEx liest Datenbankwerte egal ob diese als Zahlenwerte oder Textwerte gespeichert sind und wandelt diese intern in den passenden Datentyp Boolean um.

Bei Zahlenwerten gilt das alle Werte die nicht 0 sind als true interpretiert werden. Bei Text werten werden alle Werte die nicht "NO" oder "FALSE" sind als true interpretiert/

Die Umwandlungstabelle sieht so aus. Die Gross-kleinschreibung spielt dabei keine Rolle.

Spalten WertRückgabewert
nullfalse
"FALSE"false
"NO"false
"0"false
0false
0.0false
""false
"TRUE"true
"YES"true
"1"true
1true
1.0true
"-1"true
-1true
-1.0true
alles anderetrue

Das folgende Beispiel liest den Textwert der Spalte NAME. Enthält die Spalte NAME keinen Wert (NULL) dann wird als Wert "" zurück gegeben.

string name  = feature.GetStringEx("NAME");

Das folgende Beispiel liest den integer wert der Spalte ALTER. Enthält die Spalte ALTER keinen Wert (NULL) dann wird als Wert 0 zurück gegeben.

int alter  = feature.GetInt32Ex("ALTER");

Diese Variante liefert wenn der Spalten Wert Null ist wirklich ein NULL (NULl String) zurück

string name  = feature.GetString("NAME");

Grosse Datenmengen abfragen

Wenn Sie größere Datenmengen Abfragen müssen oder Sie innerhalb der Datensätze vor und zurück navigieren müssen sollten Sie die Klasse SqlReader bzw. FeatureReader verwenden.

Diese Klasse ruft nicht alle Datensätze auf einmal ab sondern ruft diese erst bei Bedarf in Blöcken ab. Dadurch können große Datenmengen verarbeitet werden ohne dass der Speicher überläuft.

Der erste Parameter von reader.Query ist der Name der Tabelle. Der zweite Parameter ist die Where Bedingung. Alle weiteren Parameter die einzelnen Spalten die zurueck geliefert werden sollen.

Beispiel:

Connection cn = this.Repository.GetDbConnection("LASVEGAS");
SqlReader reader = new SqlReader(cn);
reader.Query("STREET","order by FID", "FID","STRNAME");
int c = reader.RecordCount;
while (reader.MoveNext())
{
if (reader.IsRecordAvailable) //pruefen ob der Datensatz in Zwischenzeit gelöscht wurde.
{
long fid = reader.GetInt64("fid", 0);
string streetName= reader.GetString("strname", "");
}
}
reader.Close();