# ResultSet in ArrayList ablegen



## Skippy1988 (23. Mrz 2009)

Hallo,

habe folgendes Problem:

Ich möchte gern ResultSets sofort in eine ArrayList ablegen, um den Datenbankzugriff zu minimieren. Dazu habe ich mir eine Klasse ResultList geschrieben:
[highlight=Java]
public class ResultList
    {
        private ArrayList<String> Headline = new ArrayList<String>();
        private ArrayList<String> Row = new ArrayList<String>();
        private ArrayList<ArrayList> Result = new ArrayList<ArrayList>();

        private boolean MultipleColumn;

        private ArrayList<String> SingleResult = new ArrayList<String>();

        public ResultList( boolean MultipleColumn )
        {
            this.MultipleColumn = MultipleColumn;
        }

        protected void addRow()
        {
            if ( MultipleColumn )
            {
                Result.add( Row );
                Row.clear();                
            }
            else
            {
                throw new UnsupportedOperationException( "This method is not supported for single-column ResultLists." );
            }
        }

        protected void addHeadline( String Headline )
        {
            if ( MultipleColumn )
            {
                this.Headline.add(Headline);   
            }
            else
            {
                throw new UnsupportedOperationException( "This method is not supported for single-column ResultLists." );
            }
        }

        protected void addValue( String Value )
        {
            if ( MultipleColumn )
            {
                Row.add( Value );         
            }
            else
            {
                SingleResult.add( Value );
            }
        }

        protected boolean contains( int Search )
        {
            return contains( String.valueOf( Search ) );
        }

        protected boolean contains( String Search )
        {
            if ( MultipleColumn )
            {
                for ( int i=0; i<Result.size(); i++ )
                {
                    Row = Result.get( i );
                    for ( int j=0; j<Row.size(); j++ )
                    {
                        if ( Row.get( j ).equalsIgnoreCase( Search ) )
                        {
                            return true;
                        }
                    }
                }
                return false;
            }
            else
            {
                for ( int i=0; i<SingleResult.size(); i++ )
                {
                    if ( SingleResult.get( i ).equalsIgnoreCase( Search ) )
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        protected int getRowSize( int Index )
        {
            if ( MultipleColumn )
            {
                return Result.get( Index ).size();
            }
            else
            {
                throw new UnsupportedOperationException( "This method is not supported for single-column ResultLists." );
            }
        }

        protected int getSize()
        {
            if ( MultipleColumn )
            {
                return Result.size();
            }
            else
            {
                return SingleResult.size();
            }
        }

        protected String getValue( int RowIndex, String ColumnLabel )
        {
            if ( MultipleColumn )
            {
                Row = Result.get( RowIndex );
                for ( int i=0; i<Headline.size(); i++ )
                {
                    if ( ColumnLabel.equalsIgnoreCase( Headline.get( i ) ) )
                    {
                        return Row.get( i );
                    }
                }
                System.out.println( "Spalte nicht in ResultList vorhanden." );
                return null;
            }
            else
            {
                throw new UnsupportedOperationException( "This method is not supported for single-column ResultLists." );
            }
        }

        protected String getValue( int RowIndex, int ColIndex )
        {
            if ( MultipleColumn )
            {
                Row = Result.get( RowIndex );
                return Row.get( ColIndex );
            }
            else
            {
                throw new UnsupportedOperationException( "This method is not supported for single-column ResultLists." );
            }
        }

        protected String getValue( int RowIndex )
        {
            if ( MultipleColumn )
            {
                throw new UnsupportedOperationException( "This method is not supported for multiple-column ResultLists." );
            }
            else
            {
                return SingleResult.get( RowIndex );
            }
        }
    }
[/highlight]

ResultList wird dann in einer Methode getQueryResult gefüllt und zurückgegeben.
Funktioniert auch soweit. Nur wäre es mir natürlich lieber, das ganze etwas "eleganter" zu gestalten, d.h. ohne die Exceptions.
Würde gern eine Oberklasse ResultList mit den Unterklassen SingleColumnResultList und MultipleColumnResultList basteln. So wie im folgenden Code stelle ich mir den Aufruf vor. Nur leider kann ich dort die unterschiedlichen Methoden der beiden Unterklassen nicht so verlagern, wie ich das möchte. Der Kompiler nimmt ja an, es mit der (mit lediglich den gemeinsamen Methoden bestückten) Oberklasse zu tun haben...
[highlight=Java]
    protected ResultList getQueryResult( String Query, boolean MultipleCols )
    {
        ResultList List;
        if ( MultipleCols )
        {
            List = new MultipleColumnResultList();
        }
        else
        {
            List = new SingleColumnResultList();
        }
List.getRowSize; // Fehler, da getRowSize in der "neuen" Version nur noch in der Unterklasse Multi... auftaucht.
        return List;
    }
    ResultList myList = getQueryResult( "select sysdate from dual",  false);
[/highlight]

Hoffe, die Informationen reichen, um mir ein paar Tipps zu geben. (Kritik am Code ist natürlich auch erwünscht, bin ja am Lernen  )
Danke im Voraus.

MfG

Mirko


----------



## Marco13 (23. Mrz 2009)

Ich kenn mich ja mit SQL und ResultSet und so nicht aus, aber ... an welcher Stelle wird eine echte _Typunterscheidung_ zwischen Single- und Multicolumn benötigt? Ist eine SingleColumnResultList nicht einfach eine MultiColumnResultList mit nur einer Spalte?


----------



## Ebenius (23. Mrz 2009)

Ist Kritik am Konzept auch erwünscht? Ich verstehe den Nutzen nämlich nicht wirklich. Du minimierst die Datenbankzugriffe nicht. Du verringerste höchstens die Zeit während derer die ResultSets (lokal und ggf. remote, abhängig vom Cache und der jeweiligen Anfrage). Darüber hinaus baust Du aber mehr Arbeit auf der Seite des Clients auf. Hast Du dafür einen guten Grund oder eigentlich keine Entschuldigung? 

Ebenius


----------



## Skippy1988 (23. Mrz 2009)

Marco13 hat gesagt.:


> Ich kenn mich ja mit SQL und ResultSet und so nicht aus, aber ... an welcher Stelle wird eine echte _Typunterscheidung_ zwischen Single- und Multicolumn benötigt? Ist eine SingleColumnResultList nicht einfach eine MultiColumnResultList mit nur einer Spalte?



ja, "meine" SingleColu´... ist eine MultiCol... mit nur einer Spalte. beide unterscheiden sich eben in der Speicherung und im Aufruf der Daten (siehe Code oben)
wollte eben die Datenverarbeitung ein wenig erleichtern, indem ich für einspaltige Results eine eigene/modifizierte Klasse anlege.
Typunterscheidung wird a) beim füllen und b) beim lesen der Daten benötigt.



Ebenius hat gesagt.:


> Ist Kritik am Konzept auch erwünscht? Ich verstehe den Nutzen nämlich nicht wirklich. Du minimierst die Datenbankzugriffe nicht. Du verringerste höchstens die Zeit während derer die ResultSets (lokal und ggf. remote, abhängig vom Cache und der jeweiligen Anfrage). Darüber hinaus baust Du aber mehr Arbeit auf der Seite des Clients auf. Hast Du dafür einen guten Grund oder eigentlich keine Entschuldigung?
> 
> Ebenius


das meinte ich ja damit 
haben eben ein Programm, bei dem in recht hohem Umfang auf DB2 zugegriffen werden muss, in der auch ein SELECT exklusive Sperren verursacht. da das Programm recht lang für die Verarbeitung der Daten braucht, dacht ich, die Lösung mit den ArrayLists wäre ganz sinnvoll. Lass mich aber gern verbessern 

MfG,

Mirko


----------



## Ebenius (23. Mrz 2009)

Mirko, wenn Du damit einen Spezialfall abhandeln willst, dann verstehe ich nicht, wieso Du nicht eine spezielle Datenstruktur für das Problem schaffst, um das es geht. Oder handelt es sich um eine generische Datenbank-Lösung?

PS: Alle variablenNamen in Java sollten mit einem kleinem Buchstaben anfangen.

Ebenius


----------



## Luu (23. Mrz 2009)

Da übt jemand gerad Vererbung


----------



## JanHH (23. Mrz 2009)

Zumindest ist es keine Frage zum Thema "Datenbanken", sondern zum Thema "Softwaredesign".


----------



## JanHH (23. Mrz 2009)

Und nochmal dazu meinen Senf, ohne den Code verstanden zu haben:

Der Sinn von Vererbung ist es, gerade NICHT ständig Typunterscheidungen im Code zu haben. Überall liest man
[HIGHLIGHT="Java"]if ( MultipleColumn )
{
  dieses();
}
else
{
  throw new UnsupportedOperationException( "jenes" );
}[/HIGHLIGHT]
Genau das will man vermeiden. Da stimmt also irgendwas nicht.

Ansonsten scheint mir sowas wie

[HIGHLIGHT="Java"]for ( int i=0; i<SingleResult.size(); i++ )[/HIGHLIGHT]
nicht so gut, weil bei jedem Schleifendurchlauf SingleResult.size() aufgerufen wird. Das mag banal sein, aber mir kommts besser vor, das einmal abzufragen und zu speichern. Kann ja durchaus Situationen geben, wo dieser Funktionsaufruf eine gewisse Zeit benötigt.

Ansonsten kommt mir ein ORM-Ansatz generell sinnvoller vor, dann muss man sich ja gar nicht mehr mit solchen Listen rumschlagen und sie in ihre Einzelteile zerlegen, sondern hat gleich ganz einfach eine Liste der Objekte, die man in der Datenbank gespeichert hat.


----------



## Skippy1988 (24. Mrz 2009)

Ebenius hat gesagt.:


> Mirko, wenn Du damit einen Spezialfall abhandeln willst, dann verstehe ich nicht, wieso Du nicht eine spezielle Datenstruktur für das Problem schaffst, um das es geht. Oder handelt es sich um eine generische Datenbank-Lösung?


 ist eine Idee für eine allgemeine Lösung für alle Datenbanken. wollte mir eben eine "Datenbank-Klasse" schreiben, welche alle Aktivitäten bezüglich der Datenbank enthält.


Luu hat gesagt.:


> Da übt jemand gerad Vererbung


richtig. konstuktive Beiträge würden mir dabei aber eher weiterhelfen...



JanHH hat gesagt.:


> Der Sinn von Vererbung ist es, gerade NICHT ständig Typunterscheidungen im Code zu haben. Überall liest man
> [highlight="Java"]if ( MultipleColumn )
> {
> dieses();
> ...


DAS will ich ja auch vermeiden. der erste Quellcode funktioniert zwar, ist aber nicht das, was ich am Ende haben möchte. ich weiß selber, dass das Murks ist. weiß aber leider noch nicht, wie ich das folgende Problem (unabhängig vom Sinn des Konzeptes) "eleganter" lösen kann:



```
Klasse ResultList
{
übergeordnete Methoden
}

Klasse SingleColumnResultList extends ResultList
{
spezielle Methoden für einspaltiges Result
}

Klasse MultipleColumnResultList extends ResultList
{
spezielle Methoden für mehrspaltiges Result
}

...

protected ResultList getResult ( String Query, boolean mehrspaltig )
{
ResultList List;
if ( mehrspaltig ) {
List = new SingleColumnResultList;}
else {
List = new MultipleColumnResultList;}
...
List füllen
...
return List
}

ResultList List = getResult ( "select * from tbl1", true );
```



JanHH hat gesagt.:


> Ansonsten kommt mir ein ORM-Ansatz generell sinnvoller vor, dann muss man sich ja gar nicht mehr mit solchen Listen rumschlagen und sie in ihre Einzelteile zerlegen, sondern hat gleich ganz einfach eine Liste der Objekte, die man in der Datenbank gespeichert hat.


kannst du mir kurz den Ansatz erklären?

MfG,

Mirko


----------



## Luu (24. Mrz 2009)

ORM = Tabellen der Datenbank in Klassen (Entities) kapseln, für jede Spalte der Tabelle ein Feld in der Entity-Klasse
Diese Entity-Klassen könnten nun von einer Oberklasse abgeleitet werden, wo allgemeine Methoden drin stehen könnten (zb. eine fill, delete, update etc)

Bsp: Tabelle Person<Name, Vorname, Alter>
Entity: 
class Person extends Record{
private String name;
private String vorname;
private int alter;

//get,set bla
}

Objektrelationale Abbildung ? Wikipedia


----------



## Ebenius (24. Mrz 2009)

Skippy1988 hat gesagt.:


> ist eine Idee für eine allgemeine Lösung für alle Datenbanken. wollte mir eben eine "Datenbank-Klasse" schreiben, welche alle Aktivitäten bezüglich der Datenbank enthält.


Für eine allgemeine Lösung halte ich es nicht tauglich. Wenn es bestimmte Abfragen gibt, in denen alles erst gelesen und später gerechnet werden soll, dann kann man das Problem genau da lösen wo es entsteht. Das sollte die Ausnahme sein. Für eine allgemeingültige Lösung ist das Konzept der ResultSet-Klasse nicht nur ausreichend, sondern wesentlich besser.

Ebenius


----------



## JanHH (24. Mrz 2009)

Naja, die Funktion, die die ResultList erzeugt und zurückgibt, muss natürlich irgendwo diese Typunterscheidung haben. Im Grunde liegt ein Factory-Pattern vor. Eine elegante Stelle, dies zu realisieren, ist als static-Methode der abstratken Oberklasse:

```
abstract class ResultList;
{
public static ResultList getResult ( String query, boolean mehrspaltig )
{
ResultList list;
if ( mehrspaltig ) {
list = new SingleColumnResultList;}
else {
list = new MultipleColumnResultList;}
...
list füllen
...
return list
}
}
```
und Aufruf dann mit ResultList.getResultList(Query, m);

Das wäre die elegante Lösung. Frage mich aber ob man da überhaupt zwei Klassen braucht, oder ob die Klasse "mehrspalting" nicht ausreicht, und es halt die Variante "mehrspalting, mit einer Spalte" gibt, und ausserdem, ob das alles in der Form überhaupt Sinn macht. Im Endeffekt willst Du aus der ResultList ja wieder java-Objekte in irgendeiner Form zusammenbauen, und da bietet es sich eher an, das ORM-Dings zu machen (JPA ist ganz einfach, viel einfacher als per Hand mit SQL rumzumachen, finde ich). Alternativ könnte man auch die Funktionen, um eine List aus Objekten mit einer Datenbank zu verwalten, dieses als statische Funktion der Klasse der jeweiligen Objekte realsieren:


```
class MeineKlasse
{
public static void putIntoDatabase(List l);
public List readFromDatabase();
}
```

und die Funktionalitäten, die Member-Variablen des Objektes in die Datenbank zu schreiben und wieder auszulesen (und daraus die Objekte bzw. Listen von Objekten zu erzeugen) in diese Funktionen tun. Dann hättest Du bei jeder Klasse, die in die Datenbank soll, die entsprechenden Funktionen als static zur Verfügung, und müsstest diesen nur die DB-Connection als Paramter übergeben.


----------



## Skippy1988 (25. Mrz 2009)

Erst einmal vielen Dank für die konstruktiven Beiträge und Kritiken. Hilft mir sicher einiges weiter. Werde mir nachher mal das ORM-Konzept genauer ansehen und von der ResultList als allgemeine DB-Klasse Abschied nehmen.
Was mich beim 





> Da übt jemand gerad Vererbung


 dennoch interessieren würde:


JanHH hat gesagt.:


> ```
> abstract class ResultList;
> {
> public static ResultList getResult ( String query, boolean mehrspaltig )
> ...


angenommen, ich habe in der "übergeordneten" ResultList die Methoden:
 - addValue
 - contains
 - getSize
in der mehrspaltigen zusätzlich:
 - addRow
 - addHeadline
 - getRowSize
 - getValue (mehrspaltige Version)
und in der einspaltigen zusätzlich:
 - getValue (einspaltige Version)

dann kann ich doch nach dem "ResultList = new MultipleColumnResultList();" nur auf die Methoden der Klasse ResultList zugreifen, nicht auf die der MultipleColumnResultList (könnte z.B. die ResultList also nicht per addRow befüllen).
andersherum, wenn ich die Methoden als abstract mit in die ResultList nehme, habe ich von einer SingleColumnResultList Zugriff auf die Methoden, was auch nicht so toll ist.

gibt es dafür eine bessere Lösung? (ganz abgesehen von Sinn und Unsinn des gesamten Konzeptes; nur zum Verstehen)

MfG,

Mirko


----------



## JanHH (25. Mrz 2009)

Du denkst noch nicht "richtig" objektorientiert.

Das Füllen der Liste sollte eher innerhalb des Konstruktors erfolgen, und nicht von ausserhalb.

Also eher so:

[HIGHLIGHT="Java"]ResultSet myResultSet=queryAusführen(query);

if ( mehrspaltig ) {
list = new SingleColumnResultList(myResultSet);}
else {
list = new MultipleColumnResultList(myResultSet);}

und die Konstruktoren dann jeweils

SingleColumnResultList(ResultSet s)
{
// Liste füllen
}

MultiColumnResultList(ResultSet s)
{
// Liste füllen
}[/HIGHLIGHT]

so dass sich die Listen-Objekte selber aus dem ResultSet, welches aus der Abfrage resultiert, erzeugen.


----------



## Skippy1988 (25. Mrz 2009)

achso, danke.
Der Um-/Einstieg ist eben nicht so einfach 
Was passiert in diesem Falle mit dem ResultSet, welches ich nach der Bearbeitung (genau wie das Statement) sofort wieder schließen möchte?
An welcher Stelle müsste ich ResultSet und Statement schließen?

MfG,

Mirko


----------



## JanHH (25. Mrz 2009)

Hm, kenne mich mit ResultSet an sich nicht aus, aber schliessen und vergessen kannst Du es doch dann, wenn Du die Daten daraus extrahiert hast, oder?

Im code wäre das dann wohl nach dem Instanziieren der Objekte.


```
ResultSet myResultSet=queryAusführen(query);
 
if ( mehrspaltig ) {
list = new SingleColumnResultList(myResultSet);}
else {
list = new MultipleColumnResultList(myResultSet);}
 
myResultSet.closeAndForget();
```


----------



## Skippy1988 (26. Mrz 2009)

OK, jetzt hab ich es verstanden. Danke für deine Hilfe, hat mich um einiges weitergebracht.

MfG,

Mirko


----------



## JanHH (26. Mrz 2009)

na das hört man gerne .


----------

