2013-06-24 13 views
8

स्कैला का उपयोग करके कुछ डेटा पढ़ने के लिए बस मूल जेडीबीसी इंटरफेस का उपयोग कर। एफ # में (System.Data.SQL क्लाइंट नामस्थान का उपयोग करके) हम डेटाबेस से एक अपरिवर्तनीय सूची लौटने के लिए ऐसा कुछ कर सकते हैं।स्कैला सुरुचिपूर्ण सूची समझ F #

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

स्काला में यह और अधिक मुश्किल साबित होता है, मैं जानता हूँ कि जहाँ तक कोई "जबकि" समझ एफ की तरह #। प्रभावी रूप से मैं म्यूटेबल वर्र्स का उपयोग किए बिना स्काला में एफ # के करीब कुछ करना चाहता हूं - अगर केवल इसलिए कि वे बदसूरत लगते हैं और कोड ऑफ लाइन्स में जोड़ते हैं।

कुछ इस तरह अभी मेरी स्काला कोड में आम हो रहा है:

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

वास्तव में मुहावरेदार स्कैला में यह 'val rs = stmt.executeQuery() जैसा दिखता है; वैल परिणाम = के लिए (आर <- आरएस) उपज 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) 

: अपने Reader एक Iterator कन्वर्ट करने के लिए लेकिन आप इसे जोड़ सकता है यदि आप वास्तव में इस वाक्य याद कर रहे हैं:

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 काम करता है? स्कैला कंपाइलर इस अभिव्यक्ति में शामिल प्रकारों को देखता है: परिणामी प्रकार है, और मानचित्र द्वारा बुलाए गए फ़ंक्शन द्वारा लौटाया गया प्रकार है। इस जानकारी के आधार पर, स्कैला कंपाइलर एक कारखाना निहित रूप से प्रदान करता है जिसका उपयोग उपयुक्त निर्माता बनाने के लिए किया जा सकता है। इसलिए आपको विभिन्न प्रकार के संग्रहों का उत्पादन करने के लिए केवल एक विधि की आवश्यकता है।

आप एक से अधिक मान वापस जाने के लिए चाहते हैं, सिर्फ एक टपल वापसी:

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

संबंधित मुद्दे