DevTrain Startseite Visual Studio 1 Magazin  
  
  
SUCHEN:  
ARTIKEL ONLINE: 525   

Kategorien
.NET
Datenbanken
Web
XML

Allgemein
Camp
Foren
Events
Persönliche Einstellungen
Registrieren
Prämien Shop
Kontakt
Impressum
Über DevTrain

Autoren


   Autor: Klaas Wedemeyer Artikel Drucken
        
ORM Teil 2: Querys über mehrere Tabellen

Im ersten Teil habe ich gezeigt, wie einfach man mit .net Reflection in einer Datenbank lesen und schreiben kann. Was fehlt sind die Querys über mehrere Tabellen.
Die Query ist dem Lesen einer Tabelle sehr ähnlich. Der Unterschied dabei ist der Rückgabe Wert. Es werden pro Treffer mehrere Objekte zurückgegeben, von denen einige auch Null sein können. Es wäre möglich, die verknüpften Objekte in Membervariablen zurückgegeben, das setzt aber voraus, dass für alle möglichen Query entsprechende Membervariablen angelegt werden.
Ich habe mich deshalb für einen Container entschieden, der ein Dictionary implementiert

public class QueryResult : Dictionary<String, object> {}

Jedes Objekt wird in einem eigenem Eintrag gespeichert und durch den Klassenname oder einen Alias repräsentiert. Da das Dictionary case sensitive ist, muss auf die Groß und Kleinschreibung geachtet werden. Da Sql nicht case sensitive ist, muss der Objektname / Alias entsprechend eindeutig sein.
Da in verschiedenen Tabellen die gleichen Spaltennamen verwendet werden können, kann der Datareader nicht mehr mit dem Spaltennamen ausgelesen werden. Es muss direkt über den Index zugegriffen werden. Beim Lesen muss deshalb die gleiche Reihenfolge wie im Selectstatement eingehalten werden.
Für eine Query müssen als erstes die Klassen übergeben werden:
Mit der Funktion Init wird das Query Objekt aufgeräumt und das Hauptobjekt angegeben.

private void Init(Type ObjectType, string Alias)
{
    mJoins.Clear();
    mBaseObject = new Join(0, ObjectType, Alias, ??, null); mJoins.Add(Alias.Trim().ToUpper(), null);
}

Mit der Funktion Add können weitere Objekte hinzugefügt werden

private void Add(JoinType JoinType, Type ObjectType, String Alias, String Query, IDataParameter[] Parameters)
{
    Alias = Alias.Trim();
    mJoins.Add(Alias.Trim().ToUpper(), new Join(JoinType, ObjectType, Alias, Query , Parameters));
}

Und schon kann man lesen

public QueryResult[] Search(string Query, IDataParameter[] Parameters, IDbConnection Connection)
{
    IDbCommand Command = Connection.CreateCommand();
    ListBuilder ParameterList = new ListBuilder(", ");
    ListBuilder JoinList = new ListBuilder(" ");
    ListBuilder ValueList = new ListBuilder(", ");

Für das Selectstatement sammelt man erst mal die Spalten der Haupttabelle

ValueList.Add(GetValueList(mBaseObject.ObjektType, mBaseObject.Alias));

und dann die Spalten der anderen Tabellen

foreach (Join join1 in mJoins.Values)
{
    if (join1 != null)
    {
        ValueList.Add(GetValueList(join1.ObjektType, join1.Alias));

Die verschiedenen Möglichkeiten des Joins müssen mit den Tabellennamen verbunden werden

switch (join1.JoinType)
{
    case JoinType.LeftOuterJoin: JoinSql += "LEFT OUTER JOIN"; break;
    case JoinType.RightOuterJoin: JoinSql += "RIGHT OUTER JOIN"; break;
    case JoinType.OuterJoin: JoinSql += "OUTER JOIN"; break;
    case JoinType.InnerJoin: JoinSql += "INNER JOIN"; break;
    case JoinType.CrossJoin: JoinSql += "CROSS JOIN"; break;
}
JoinSql += " " + GetTableName(join1.ObjektType) + " " + join1.Alias;

Am Schluss wird die Bedingung angefügt

if (join1.Query.Trim() != "")
    JoinSql += " ON " + join1.Query;
if (join1.Parameters != null)
    foreach (IDataParameter Parameter in join1.Parameters)
         Command.Parameters.Add(Parameter);
JoinList.Add(JoinSql);
}}

Daraus kann man das Sql erstellen

ListBuilder Sql = new ListBuilder(" ");
            Sql.Add("SELECT " + ValueList);
            Sql.Add("FROM " + GetTableName(mBaseObject.ObjektType) + " " + mBaseObject.Alias);
            Sql.Add(JoinList.ToString());
            if (Query.Trim()!="")
                Sql.Add("WHERE " + Query);

foreach (IDataParameter Parameter in Parameters)
                Command.Parameters.Add(Parameter);

List<QueryResult> Result = new List<QueryResult>();

und ausführen

IDataReader Reader = Command.ExecuteReader();
Für jeden Treffer
while (Reader.Read())
{
    QueryResult ResultLine = new QueryResult();

wird zuerst das Hauptobjekt gelesen

int Index = 0;
    ResultLine.Add(mBaseObject.Name, ReadObject(mBaseObject.ObjektType, mBaseObject.Alias, Reader, ref Index));

und dann in der richtigen Reihenfolge alle Weiteren

    foreach (Join join2 in mJoins.Values)
    {
         if (join2 != null)
        {
            ResultLine.Add(join2.Name, ReadObject(join2.ObjektType, join2.Alias, Reader, ref Index));
        }
    }
    Result.Add(ResultLine);
}
Reader.Close();
return Result.ToArray();

das wars. Der Aufruf ist genauso einfach

Connection.Open();
ORQuerySqlServer orq = new ORQuerySqlServer();
orq.Init(typeof(Contract), "Con");
orq.Add(JoinType.LeftOuterJoin, typeof(Customer), "Cus1", "Con.Customer1Id=Cus1.Id");
IdataParameter[] Parameters = {new SqlParameter("@Text", "Hallo")};
QueryResult[] Result = orq.Search("Con.Text LIKE @Text", Parameters, Connection);
Connection.Close();

Auf meiner Homepage findet Ihr den ausführlichen Code und ein kleines Beispiel.
Im dritten Teil stelle ich Euch eine Möglichkeit vor, wie die Anwendung die Tabellen in der DB selbstständig erzeugt und verwaltet.

Bis dahin,
Klaas Wedemeyer


DevTrain Camp - Schneller zum .NET 3.5 Developer
 
Verwandte Artikel      Verlinkte Dokumente
    Keine verknüpften Dokumente
    Keine Links vorhanden

  Erfasst am: 10.05.2006
  Gültig bis: 08.08.2006
3 Ratings
Bewertung: 86,7%
schlecht    sehr gut  

 
© Copyright 2007 ppedv AG