Question

J'ai un ensemble de lignes dans une base de données, et je voudrais fournir une interface pour filer à travers eux comme ceci:

def findAll: Iterable[MyObject]

Si nous ne demandons pas d'avoir toutes les instances en mémoire à la fois. En C #, vous pouvez facilement créer des générateurs comme celui-ci en utilisant le rendement, le compilateur prend en charge la conversion du code qui boucle à travers le jeu d'enregistrements dans un iterator (sorte de l'inverser).

Mon code actuel ressemble à ceci:

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

Est-il possible que je pourrais convertir ce pour ne pas stocker l'ensemble dans la mémoire? Peut-être que je pourrais utiliser une pour la compréhension?

Était-ce utile?

La solution

Essayez étendre à la place Iterator. Je ne l'ai pas testé, mais quelque chose comme ceci:

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

Cela devrait stocker rs quand il est appelé, et sinon juste un emballage léger pour les appels vers rs.

Si vous souhaitez enregistrer les valeurs que vous traversez, consultez Stream.

Autres conseils

Je suis tombé sur le même problème et sur la base des idées ci-dessus, j'ai créé la solution suivante en écrivant une classe d'adaptateur:

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

Avec cela, vous pouvez par exemple effectuer carte opérations sur le jeu de résultats - qui était mon intention personnelle:

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

Ajoute une .toList afin de forcer l'évaluation. Ceci est utile si la connexion de base de données est fermée avant d'utiliser les valeurs. Sinon, vous obtiendrez une erreur en disant que vous ne pouvez pas accéder au ResultSet après la connexion a été fermée.

Une simple (idiomatiques) façon d'obtenir le même serait

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

Vous avez besoin du .toList pour forcer l'évaluation, sinon la collection sous-jacente sera un cours d'eau et le ResultSet peut être fermé avant l'évaluation a eu lieu.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top