*
วิธีการ:
สิ่งนี้จะส่งคืนการฉายภาพเริ่มต้นซึ่งเป็นวิธีที่คุณอธิบาย:
'คอลัมน์ทั้งหมด (หรือค่าที่คำนวณแล้ว) ฉันมักจะสนใจ'
ตารางของคุณอาจมีหลายช่อง คุณต้องการเพียงส่วนย่อยสำหรับการฉายภาพเริ่มต้นของคุณ การฉายภาพเริ่มต้นต้องตรงกับพารามิเตอร์ประเภทของตาราง
ลองมาดูทีละเรื่อง หากไม่มี<>
สิ่งของเพียงแค่*
:
object Bars extends Table[(Int, String)]("bar") {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
def name = column[String]("name")
def * = id ~ name
}
คำจำกัดความตารางแบบนี้จะช่วยให้คุณสร้างแบบสอบถามเช่น:
implicit val session: Session =
val result = Query(Bars).list
การฉายภาพเริ่มต้นของ(Int, String)
โอกาสในการขายไปยังList[(Int, String)]
ข้อความค้นหาแบบง่ายเช่นนี้
val q =
for (b <- Bars if b.id === 42)
yield (b.name ~ 1)
ประเภทของq
อะไร? มันเป็นที่มีการฉายQuery
(String, Int)
เมื่อเรียกมันส่งกลับList
ของ(String, Int)
tuples ตามประมาณการ
val result: List[(String, Int)] = q.list
ในกรณีนี้คุณได้กำหนดการฉายภาพที่คุณต้องการในyield
ประโยคของความfor
เข้าใจ
ตอนนี้เกี่ยวกับ<>
และBar.unapply
.
แห่งนี้มีสิ่งที่เรียกว่าการประมาณการแมป
จนถึงตอนนี้เราได้เห็นแล้วว่า Slick ช่วยให้คุณแสดงข้อความค้นหาใน Scala ที่ส่งคืนการฉายภาพของคอลัมน์ (หรือค่าที่คำนวณได้) ได้อย่างไร ดังนั้นเมื่อมีการดำเนินการค้นหาเหล่านี้คุณต้องคิดของแถวผลของแบบสอบถามเป็น tuple ประเภทของทูเปิลจะตรงกับการฉายภาพที่กำหนดไว้ (ตามfor
ความเข้าใจของคุณ
ดังตัวอย่างก่อนหน้าของการ*
ฉายภาพเริ่มต้น) นี่คือเหตุผลที่field1 ~ field2
ส่งคืนการคาดการณ์Projection2[A, B]
ว่าA
เป็นประเภทของที่ไหน
field1
และB
เป็นประเภทของfield2
.
q.list.map {
case (name, n) =>
}
Queury(Bars).list.map {
case (id, name) =>
}
เรากำลังจัดการกับสิ่งที่เพิ่มขึ้นซึ่งอาจยุ่งยากหากเรามีคอลัมน์มากเกินไป เราไม่ต้องการคิดถึงผลลัพธ์TupleN
แต่เป็นวัตถุบางอย่างที่มีฟิลด์ที่มีชื่อ
(id ~ name)
case class Bar(id: Int, name: String)
(id ~ name <> (Bar, Bar.unapply _))
Query(Bars).list.map ( b.name )
วิธีนี้ทำงานอย่างไร? <>
ใช้เวลาการฉายและผลตอบแทนประมาณการที่แมปกับชนิดProjection2[Int, String]
Bar
อาร์กิวเมนต์ทั้งสองBar, Bar.unapply _
บอกว่า(Int, String)
ต้องแมปการฉายภาพนี้กับคลาสเคสอย่างไร
นี่คือการทำแผนที่สองทาง Bar
เป็นตัวสร้างคลาสเคสดังนั้นนั่นคือข้อมูลที่จำเป็นในการเปลี่ยนจาก(id: Int, name: String)
เป็นBar
ไฟล์. และunapply
ถ้าคุณเดาได้ก็คือการย้อนกลับ
ในกรณีที่ไม่unapply
มาจากไหน? นี้เป็นวิธีที่ Scala มาตรฐานที่สามารถใช้ได้สำหรับการเรียนกรณีใด ๆ สามัญ - เพียงแค่กำหนดBar
จะช่วยให้คุณBar.unapply
ซึ่งเป็นแยกที่สามารถนำมาใช้เพื่อให้ได้กลับมาid
และname
ที่
Bar
ถูกสร้างขึ้นด้วย:
val bar1 = Bar(1, "one")
val Bar(id, name) = bar1
val bars: List[Bar] =
val barNames = bars.map {
case Bar(_, name) => name
}
val x = Bar.unapply(bar1)
ดังนั้นการฉายภาพเริ่มต้นของคุณจึงสามารถแมปกับคลาสเคสที่คุณคาดว่าจะใช้มากที่สุด:
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)
val q1 =
for (b <- Bars if b.id === 42)
yield (b.name ~ 1 <> (Baz, Baz.unapply _))
นี่คือประเภทของการq1
เป็นผู้Query
ที่มีแมปBaz
การฉายไป เมื่อเรียกมันส่งกลับList
ของBaz
วัตถุ:
val result: List[Baz] = q1.list
ในที่สุดนอกจาก.?
นี้ข้อเสนอการยกตัวเลือก - วิธีการจัดการกับค่านิยมของสกาล่าที่อาจไม่เป็นเช่นนั้น
(id ~ name)
(id.? ~ name)
ซึ่งการสรุปจะทำงานได้ดีกับคำจำกัดความดั้งเดิมของคุณคือBar
:
case class Bar(id: Option[Int] = None, name: String)
val q0 =
for (b <- Bars if b.id === 42)
yield (b.id.? ~ b.name <> (Bar, Bar.unapply _))
q0.list
เพื่อตอบสนองต่อความคิดเห็นเกี่ยวกับวิธีที่ Slick ใช้for
ความเข้าใจ:
อย่างไรก็ตาม monads มักจะปรากฏตัวและเรียกร้องให้เป็นส่วนหนึ่งของคำอธิบาย ...
เพื่อความเข้าใจไม่ได้เจาะจงเฉพาะคอลเลกชันเท่านั้น อาจใช้กับMonadประเภทใดก็ได้และคอลเลกชันเป็นเพียงหนึ่งในประเภท Monad หลายประเภทที่มีอยู่ใน Scala
แต่เนื่องจากคอลเลกชันเป็นที่คุ้นเคยพวกเขาจึงเป็นจุดเริ่มต้นที่ดีสำหรับคำอธิบาย:
val ns = 1 to 100 toList;
val result =
for { i <- ns if i*i % 2 == 0 }
yield (i*i)
ใน Scala a for comp understandion คือน้ำตาลวากยสัมพันธ์สำหรับการเรียกเมธอดเมธอด (อาจซ้อนกัน): โค้ดด้านบน (มากหรือน้อย) เทียบเท่ากับ:
ns.filter(i => i*i % 2 == 0).map(i => i*i)
โดยทั่วไปอะไรกับfilter
, map
, flatMap
วิธีการ (ในคำอื่น ๆMonad ) สามารถนำมาใช้ใน
ความเข้าใจในสถานที่ของfor
ns
ตัวอย่างที่ดีคือmonad ตัวเลือก นี่คือตัวอย่างก่อนหน้านี้ที่เดียวกันfor
คำสั่งการทำงานทั้งบน
List
เช่นเดียวกับOption
monads:
val result =
for {
i <- ns
i2 <- Some(i*i)
if i2 % 2 == 0
} yield i2
def evenSqr(n: Int) = {
val sqr = n*n
if (sqr % 2 == 0) Some (sqr)
else None
}
result =
for {
i <- ns
i2 <- evenSqr(i)
} yield i2
ในตัวอย่างสุดท้ายการเปลี่ยนแปลงอาจมีลักษณะดังนี้:
val result =
ns.flatMap(i => Some(i*i)).filter(i2 => i2 %2 ==0)
result =
ns.flatMap(i => evenSqr(i))
ในเนียนแบบสอบถามเป็นเอก - พวกเขาเป็นวัตถุเพียงกับmap
, flatMap
และfilter
วิธีการ ดังนั้นความfor
เข้าใจ (แสดงในคำอธิบายของ*
วิธีการ) จึงแปลเป็น:
val q =
Query(Bars).filter(b => b.id === 42).map(b => b.name ~ 1)
val r: List[(String, Int)] = q.list
ในขณะที่คุณสามารถดูflatMap
, map
และfilter
ถูกนำมาใช้ในการสร้างQuery
โดยการเปลี่ยนแปลงที่ซ้ำQuery(Bars)
กับการภาวนาของแต่ละและfilter
map
ในกรณีของคอลเล็กชันวิธีการเหล่านี้จะวนซ้ำและกรองคอลเล็กชัน แต่ใน Slick จะใช้เพื่อสร้าง SQL รายละเอียดเพิ่มเติมที่นี่:
Scala Slick แปลโค้ด Scala เป็น JDBC ได้อย่างไร