2013-06-24 3 views
8

기본 JDBC 인터페이스를 사용하여 스칼라를 사용하여 일부 데이터를 읽는 것만으로. F # (System.Data.SqlClient 네임 스페이스 사용)에서 이와 같은 작업을 수행하여 데이터베이스에서 불변 목록을 반환 할 수 있습니다.F #에서와 같이 스칼라의 우아한 목록 이해.

let rs = cmd.ExecuteReader() 
    [while rs.Read() do yield rs.GetInt32(1)] 

스칼라에서 이것은 F #과 같은 "while"독해력이 없다는 것을 알고있는 한 더욱 어렵습니다. 효과적으로 나는 가변적 인 vars를 사용하지 않고 스칼라에서 F #에 가깝게하고 싶습니다. 단지 추한 것처럼 보이고 코드 라인에 추가하기 때문입니다.

이 같은

뭔가 지금 내 스칼라 코드에서 일반화 될 것으로 보인다 :

var result = Seq.empty[Int] 
val rs = stmt.executeQuery() 
while (rs.next()) { 
    result = result :+ rs.getInt(1) } 
+3

실제로 관용적 인 스칼라에서는 'val rs = stmt.executeQuery(); val result = for (r-rs) yield r.getInt (1)'(단지 의사 코드라면) –

+0

이 게시물을보실 수 있습니다 : http://stackoverflow.com/questions/2102662/scala-exposing-a-jdbc-resultset-through-a-generator-iterable/15950556 # 15950556 –

+2

스칼라에서 LINQ와 유사한 쿼리를 찾으려면 [Slick] (http : // slick. typesafe.com/) –

답변

9

나는 쿼리 결과를 래핑 Iterator의 사용자 지정 하위 클래스를 만들 것이다. 정말 쉽습니다. 세 니아가 방법을 보여 줬어.

은 그러나 당신은 또한

val rs = stmt.executeQuery 
val it = Iterator.continually(if (rs.next()) Some(rs.getInt(1)) else None) 
val result = it.takeWhile(_.isDefined).toList.flatten 
7

당신은 스칼라에서 같은 방법을 사용할 수 있지만 나는 그것이 추한 생각 :

class Reader(var i: Int){ 
    def read = { i-=1; i > 0 } 
    def getInt32 = i 
} 

val r = new Reader(10) 
Stream.from(0).takeWhile{ _ => r.read}.map{ _ => r.getInt32}.toList 
// List(9, 8, 7, 6, 5, 4, 3, 2, 1) 

개성있는 스칼라 방법입니다

implicit class ReaderIterator(r: Reader) extends Iterator[Int] { 
    def hasNext = r.read 
    def next = r.getInt32 
} 

scala> new Reader(10).toList 
res0: List[Int] = List(9, 8, 7, 6, 5, 4, 3, 2, 1) 

: 당신의 ReaderIterator에 변환하는 당신이 정말로이 구문을 누락하지만 당신은 그것을 추가 할 수 있습니다

import scala.collection.immutable.VectorBuilder 
class FWhile(c: => Boolean){ 
    def apply[T](e: => T): Seq[T] = { 
    val b = new VectorBuilder[T] 
    while (c) b += e 
    b.result 
    } 
} 
object FWhile{ 
    def apply(c: => Boolean) = new FWhile(c) 
} 

scala> FWhile(r.read){r.getInt32} 
res0: Seq[Int] = Vector(9, 8, 7, 6, 5, 4, 3, 2, 1) 
+0

좋은 답변입니다. 여기에있는 다른 모든 응답도 너무 우수합니다. –

5

당신은 암시 적 CanBuildFrom과 함께 암시 클래스를 사용할 수 있습니다. 당신이 map을 직접 선호하는, 그래서 만약

는 이해에 대한
import MyResultSetContainer._ 
val rs = stmnt.executeQuery("select * from pg_user") 

val names = for (row <- rs) yield (row.getString(1)) 

println(names) 
rs.close() 

(가) 후드 map을 사용

object MyResultSetContainer { 
    implicit class MyResultSet(rs: ResultSet) { 
    def map[T, C <: Iterable[T]](f: (ResultSet) => T) 
           (implicit cbf: CanBuildFrom[Nothing, T, C]): C = { 
     val builder = cbf() 
     while (rs.next()) { 
     builder += f(rs) 
     } 
     builder.result() 
    } 
    } 
} 

은 다음과 같이 사용하는이 호출자의 측면에서 변경 가능한 빌더를 사용하지 아니지만 :

val names = rs.map(row => row.getString(1)) 

이는 서열을 생성한다. CanBuildFrom 덕분에 명시 적으로 유형을 제공하여뿐만 아니라 다른 컬렉션을 생성 할 수 있습니다 :

val names: List[String] = rs.map(row => row.getString(1)) 

어떻게 CanBuildFrom 작동합니까? Scala 컴파일러는이 표현식과 관련된 유형을 찾습니다. 결과 유형과 map이 호출 한 함수가 반환 한 유형이 있습니다. 이 정보를 기반으로 Scala 컴파일러는 적절한 빌더를 만드는 데 사용할 수있는 암시 적으로 팩토리를 제공합니다. 따라서 다른 유형의 콜렉션을 생성하는 한 가지 방법 만 필요합니다.여러 값을 반환 할 경우

, 그냥 튜플 반환 :

val columns = rs.map(row => (row.getInt(2), row.getString(1))) 

및 튜플 생성하는 데 사용할 수있는 Map 직접 :

val keyNamesMap: Map[Int, String] = 
    rs.map(row => (row.getInt(2), row.getString(1))) 

이는 아이디어를 기반으로하는 결과 집합은 행 목록이므로 map 함수가 그 위에 있어야합니다. 암시 적 클래스는 암시 적으로 기본 결과 집합에 map 메서드를 추가하는 데 사용됩니다.

+0

'CanBuildFrom'에 대한 마법을 설명 할 가치가 있습니다 .-) –

+0

@ om-nom-nom 그러나 이것은 마법을 파괴 할 것입니다 :-) 나는 설명을 추가했습니다. – Beryllium