*วิธีการ:
สิ่งนี้จะส่งคืนการฉายภาพเริ่มต้นซึ่งเป็นวิธีที่คุณอธิบาย:
'คอลัมน์ทั้งหมด (หรือค่าที่คำนวณแล้ว) ฉันมักจะสนใจ'
ตารางของคุณอาจมีหลายช่อง คุณต้องการเพียงส่วนย่อยสำหรับการฉายภาพเริ่มต้นของคุณ การฉายภาพเริ่มต้นต้องตรงกับพารามิเตอร์ประเภทของตาราง
ลองมาดูทีละเรื่อง หากไม่มี<>สิ่งของเพียงแค่*:
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เช่นเดียวกับOptionmonads:
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 ได้อย่างไร