14 Stimmen

Scala: Ein JDBC ResultSet durch einen Generator (iterable) freigeben

Ich habe eine Reihe von Zeilen in einer Datenbank, und ich möchte eine Schnittstelle, um durch sie wie folgt zu spinnen:

def findAll: Iterable[MyObject]

Wir brauchen nicht alle Instanzen gleichzeitig im Speicher zu haben. In C# können Sie leicht Generatoren wie diese mit Yield erstellen, der Compiler kümmert sich um die Umwandlung von Code, der Schleifen durch den Datensatz in einen Iterator (eine Art Invertierung).

Mein aktueller Code sieht wie folgt aus:

def findAll: List[MyObject] = {
  val rs = getRs
  val values = new ListBuffer[MyObject]
  while ( rs.next() ) 
    values += new valueFromResultSet(rs)
  values.toList
}

Gibt es eine Möglichkeit, dies so umzuwandeln, dass nicht der gesamte Satz im Speicher gespeichert wird? Vielleicht könnte ich ein for comprehension verwenden?

15voto

Björn Jacobs Punkte 3840

Ich stieß auf das gleiche Problem und auf der Grundlage der oben genannten Ideen habe ich die folgende Lösung erstellt, indem ich einfach eine Adapterklasse geschrieben habe:

class RsIterator(rs: ResultSet) extends Iterator[ResultSet] {
    def hasNext: Boolean = rs.next()
    def next(): ResultSet = rs
}

Damit können Sie z.B. Folgendes durchführen Karte Operationen auf die Ergebnismenge - was meine persönliche Absicht war:

val x = new RsIterator(resultSet).map(x => {
    (x.getString("column1"), x.getInt("column2"))
})

Anhängen einer .toList um eine Bewertung zu erzwingen. Dies ist nützlich, wenn die Datenbankverbindung geschlossen wird, bevor Sie die Werte verwenden. Andernfalls erhalten Sie eine Fehlermeldung, die besagt, dass Sie nicht auf das ResultSet zugreifen können, nachdem die Verbindung geschlossen wurde.

13voto

Rex Kerr Punkte 164629

Versuchen Sie stattdessen, Iterator zu erweitern. Ich habe es nicht getestet, aber etwas wie dieses:

def findAll: Iterator[MyObject] = new Iterator[MyObject] {
  val rs = getRs
  override def hasNext = rs.hasNext
  override def next = new valueFromResultSet(rs.next)
}

Dies sollte rs speichern, wenn es aufgerufen wird, und ansonsten nur ein leichter Wrapper für Aufrufe an rs sein.

Wenn Sie die Werte, die Sie durchlaufen, speichern möchten, sollten Sie sich Stream ansehen.

7voto

TimT Punkte 1496

Eine einfachere (idiomatische) Möglichkeit, dasselbe zu erreichen, wäre

Iterator.continually((rs.next(), rs)).takeWhile(_._1).map(r => valueFromResultSet(r._2)).toList

Sie benötigen die .toList um die Auswertung zu erzwingen, andernfalls ist die zugrunde liegende Auflistung ein Stream und das ResultSet kann geschlossen werden, bevor die Auswertung stattgefunden hat.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X