*
विधि:
यह डिफ़ॉल्ट प्रक्षेपण रिटर्न - जो है आप कैसे वर्णन:
'सभी कॉलम (या अभिकलन मान) मैं आमतौर पर कर रहा हूँ रुचि' में
आपका तालिका कई क्षेत्रों हो सकता था।; आपको केवल के लिए अपने डिफ़ॉल्ट प्रक्षेपण के लिए एक सबसेट की आवश्यकता है। डिफ़ॉल्ट प्रक्षेपण तालिका के पैरामीटर से मेल खाना चाहिए।
चलिए इसे एक समय में लेते हैं।<>
सामान के बिना, बस *
:
// First take: Only the Table Defintion, no case class:
object Bars extends Table[(Int, String)]("bar") {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
def name = column[String]("name")
def * = id ~ name // Note: Just a simple projection, not using .? etc
}
// Note that the case class 'Bar' is not to be found. This is
// an example without it (with only the table definition)
बस ऐसे ही एक मेज परिभाषा आप की तरह के प्रश्नों बनाने देंगे:
implicit val session: Session = // ... a db session obtained from somewhere
// A simple select-all:
val result = Query(Bars).list // result is a List[(Int, String)]
(Int, String)
के डिफ़ॉल्ट प्रक्षेपण सरल प्रश्नों इस तरह के लिए एक List[(Int, String)]
की ओर जाता है इन जैसे।
// SELECT b.name, 1 FROM bars b WHERE b.id = 42;
val q =
for (b <- Bars if b.id === 42)
yield (b.name ~ 1)
// yield (b.name, 1) // this is also allowed:
// tuples are lifted to the equivalent projection.
q
का प्रकार क्या है? प्रक्षेपण (String, Int)
के साथ यह Query
है। जब लागू किया जाता है, तो यह प्रक्षेपण के अनुसार (String, Int)
tuples के List
देता है।
val result: List[(String, Int)] = q.list
इस मामले में, आप प्रक्षेपण आप for
समझ की yield
खंड में चाहते परिभाषित किया है।
अब लगभग <>
और Bar.unapply
।
यह मैप किए गए अनुमान कहलाता है।
अब तक हमने देखा है कि स्काल में क्वेरी कैसे व्यक्त करने की अनुमति देता है जो कॉलम (या गणना मूल्य) के प्रक्षेपण को वापस लौटाता है; तो निष्पादित करते समय इन प्रश्नों आपको एक प्रश्न के परिणाम पंक्ति के परिणाम स्केल टुपल के रूप में सोचना होगा। टुपल का प्रकार परिभाषित प्रक्षेपण से मेल खाता है (आपके for
पिछले उदाहरण के अनुसार डिफ़ॉल्ट *
प्रक्षेपण द्वारा समझ में आता है)। यही कारण है कि field1 ~ field2
Projection2[A, B]
का प्रक्षेपण देता है जहां A
field1
और B
का प्रकार field2
का प्रकार है।
q.list.map {
case (name, n) => // do something with name:String and n:Int
}
Queury(Bars).list.map {
case (id, name) => // do something with id:Int and name:String
}
हम tuples, जो बोझिल अगर हम भी कई स्तंभ हो सकता है के साथ काम कर रहे हैं। हम परिणामों के बारे में सोचना नहीं चाहते हैं TupleN
बल्कि नामित फ़ील्ड वाले कुछ ऑब्जेक्ट।
(id ~ name) // A projection
// Assuming you have a Bar case class:
case class Bar(id: Int, name: String) // For now, using a plain Int instead
// of Option[Int] - for simplicity
(id ~ name <> (Bar, Bar.unapply _)) // A MAPPED projection
// Which lets you do:
Query(Bars).list.map (b.name)
// instead of
// Query(Bars).list.map { case (_, name) => name }
// Note that I use list.map instead of mapResult just for explanation's sake.
यह कैसे काम करता है? <>
प्रक्षेपण Projection2[Int, String]
और Bar
पर एक मैप किए गए प्रक्षेपण को वापस लेता है। दो तर्क Bar, Bar.unapply _
बताएं कि यह (Int, String)
प्रोजेक्शन को किसी केस क्लास में मैप किया जाना चाहिए।
यह दो-तरफा मैपिंग है; Bar
केस क्लास कन्स्ट्रक्टर है, इसलिए (id: Int, name: String)
से Bar
पर जाने के लिए आवश्यक जानकारी है। और unapply
यदि आपने अनुमान लगाया है, तो रिवर्स के लिए है।
unapply
कहां से आता है?
: बस को परिभाषित करने Bar
आप एक Bar.unapply
जो एक निकालने कि id
और name
कि Bar
साथ बनाया गया था वापस पाने के लिए इस्तेमाल किया जा सकता है देता है - यह एक मानक स्काला विधि के लिए उपलब्ध किसी भी साधारण मामला वर्ग है val bar1 = Bar(1, "one")
// later
val Bar(id, name) = bar1 // id will be an Int bound to 1,
// name a String bound to "one"
// Or in pattern matching
val bars: List[Bar] = // gotten from somewhere
val barNames = bars.map {
case Bar(_, name) => name
}
val x = Bar.unapply(bar1) // x is an Option[(String, Int)]
तो अपने डिफ़ॉल्ट प्रक्षेपण मामले वर्ग के लिए मैप किया जा सकता आप सबसे अधिक उपयोग करने की उम्मीद:
object Bars extends Table[Bar]("bar") {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
def name = column[String]("name")
def * = id ~ name <>(Bar, Bar.unapply _)
}
या आप भी यह हो सकता है प्रति-प्रश्न:
case class Baz(name: String, num: Int)
// SELECT b.name, 1 FROM bars b WHERE b.id = 42;
val q1 =
for (b <- Bars if b.id === 42)
yield (b.name ~ 1 <> (Baz, Baz.unapply _))
यहाँ q1
के प्रकार के एक के साथ एक Query
Baz
को प्रक्षेपण मैप किया गया है। जब लागू, यह Baz
के List
वस्तुओं रिटर्न:
val result: List[Baz] = q1.list
अंत में, एक अलग रूप में, .?
विकल्प भारोत्तोलन प्रदान करता है के रूप में - की स्काला रास्ता मान जो नहीं हो सकता है के साथ काम कर।
(id ~ name) // Projection2[Int, String] // this is just for illustration
(id.? ~ name) // Projection2[Option[Int], String]
कौन सा, ऊपर लपेटकर, Bar
के अपने मूल परिभाषा के साथ अच्छी तरह से काम करेगा:
case class Bar(id: Option[Int] = None, name: String)
// SELECT b.id, b.name FROM bars b WHERE b.id = 42;
val q0 =
for (b <- Bars if b.id === 42)
yield (b.id.? ~ b.name <> (Bar, Bar.unapply _))
q0.list // returns a List[Bar]
टिप्पणी के जवाब में पर कैसे स्लिक का उपयोग करता है for
comprehensions:
किसी तरह, monads हमेशा को दिखाने और मांग करने का प्रबंधन स्पष्टीकरण का हिस्सा बनें ...
समझ के लिए केवल संग्रह के लिए विशिष्ट नहीं हैं। उनका उपयोग किसी भी प्रकार के मोनाड पर किया जा सकता है, और संग्रह स्कैला में उपलब्ध कई प्रकार के मोनड प्रकारों में से एक है।
लेकिन जैसे संग्रह परिचित हैं, वे एक अच्छा प्रारंभिक बिंदु एक स्पष्टीकरण के लिए करते हैं:
val ns = 1 to 100 toList; // Lists for familiarity
val result =
for { i <- ns if i*i % 2 == 0 }
yield (i*i)
// result is a List[Int], List(4, 16, 36, ...)
स्काला में, समझ के लिए एक वाक्यात्मक चीनी विधि (संभवतः नेस्ट) विधि कॉल के लिए है: उपरोक्त कोड है (कम या ज्यादा) बराबर करने के लिए:
ns.filter(i => i*i % 2 == 0).map(i => i*i)
असल में, filter
के साथ कुछ भी, map
, flatMap
विधियों (दूसरे शब्दों में, मोनाड) ns
की जगह for
समझ में उपयोग किया जा सकता है। एक अच्छा उदाहरण Option monad है।यहाँ पिछले उदाहरण जहां एक ही for
बयान दोनों List
पर काम करता है और साथ ही Option
monads है:
// (1)
val result =
for {
i <- ns // ns is a List monad
i2 <- Some(i*i) // Some(i*i) is Option
if i2 % 2 == 0 // filter
} yield i2
// Slightly more contrived example:
def evenSqr(n: Int) = { // return the square of a number
val sqr = n*n // only when the square is even
if (sqr % 2 == 0) Some (sqr)
else None
}
// (2)
result =
for {
i <- ns
i2 <- evenSqr(i) // i2 may/maynot be defined for i!
} yield i2
पिछले उदाहरण में, परिवर्तन शायद लगेगा इस तरह:
// 1st example
val result =
ns.flatMap(i => Some(i*i)).filter(i2 => i2 %2 ==0)
// Or for the 2nd example
result =
ns.flatMap(i => evenSqr(i))
Slick में, प्रश्न monadic हैं - वे केवल map
, flatMap
और filter
विधियों के साथ ऑब्जेक्ट्स हैं। तो for
समझ (*
विधि के विवरण में दिखाया गया है) सिर्फ तब्दील करने के लिए:
val q =
Query(Bars).filter(b => b.id === 42).map(b => b.name ~ 1)
// Type of q is Query[(String, Int)]
val r: List[(String, Int)] = q.list // Actually run the query
आप देख सकते हैं, flatMap
, map
और filter
लिए उपयोग किया जाता Query(Bars)
के बार-बार परिवर्तन द्वारा एक Query
उत्पन्न filter
और map
के प्रत्येक आमंत्रण के साथ। संग्रहों के मामले में इन विधियों को वास्तव में पुन: सक्रिय करें और संग्रह फ़िल्टर करें लेकिन स्लिक में उनका उपयोग SQL उत्पन्न करने के लिए किया जाता है। यहां अधिक जानकारी: How does Scala Slick translate Scala code into JDBC?
सुंदर जवाब। –
'1' स्पष्टीकरण ब्लॉक में: यह स्पष्ट नहीं है कि 'val q =' WrappingQuery है, यह कोड पढ़ने के दौरान एक सूची जैसा दिखता है। यह कैसे संभव है कि यह क्वेरी में बदल जाता है ..? (मैं अभी भी यह समझने के लिए आपके स्पष्टीकरण के साथ खेल रहा हूं कि यह कैसे काम करता है। इसके लिए धन्यवाद!) –
ses
@ses - इस बारे में एक (थोड़ा लंबा) स्पष्टीकरण जोड़ा गया ... इसके अलावा, http://stackoverflow.com/questions पर देखें/13454347/monads-with-java-8/13455602 # 13455602 - मुझे एहसास हुआ कि यह लगभग एक ही सामग्री है। – Faiz