*
방법 :
이렇게하면 기본 투영 이 반환됩니다 .
' 일반적으로 관심있는 모든 열 (또는 계산 된 값) '.
테이블에는 여러 필드가있을 수 있습니다. 기본 프로젝션에 대한 하위 집합 만 필요합니다. 기본 프로젝션은 테이블의 유형 매개 변수와 일치해야합니다.
한 번에 하나씩 가져 가자. <>
물건이 없으면 *
:
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)
투사에 따라 튜플.
val result: List[(String, Int)] = q.list
이 경우 이해 의 yield
절 에서 원하는 투영을 정의했습니다 for
.
이제 <>
및 Bar.unapply
.
이것은 Mapped Projections 라는 것을 제공합니다 .
지금까지 우리는 열 (또는 계산 된 값) 의 프로젝션 을 반환하는 쿼리를 Scala에서 얼마나 매끄럽게 표현할 수 있는지 살펴 보았습니다 . 따라서 이러한 쿼리 를 실행할 때 쿼리 의 결과 행 을 Scala 튜플 이라고 생각해야합니다 . 튜플의 유형은 정의 된 프로젝션과 일치합니다 (
for
이전 예제에서와 같이 기본 *
프로젝션 에 의한 이해에 의해 ). 이것이 where
is the type of and is the type of 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) // For now, using a plain Int instead
(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
에서 왔습니까? 이것은 어떤 보통의 경우 클래스에 사용할 수있는 표준 스칼라 방법입니다 - 단지 정의가 Bar
있는 A에게 제공 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
A는 Query
A의 매핑 에 투영 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
이해력을 사용하는 방법에 대한 의견에 대한 답변 :
어쨌든 모나드는 항상 나타나서 설명의 일부가 될 것을 요구합니다 ...
이해력은 컬렉션에만 국한되지 않습니다. 모든 종류의 Monad 에서 사용할 수 있으며 컬렉션은 Scala에서 사용할 수있는 많은 종류의 모나드 유형 중 하나 일뿐입니다.
그러나 컬렉션은 익숙하기 때문에 설명을위한 좋은 출발점이됩니다.
val ns = 1 to 100 toList;
val result =
for { i <- ns if i*i % 2 == 0 }
yield (i*i)
Scala에서 for comprehension은 메서드 (중첩 된) 메서드 호출에 대한 구문 설탕입니다. 위 코드는 다음과 같습니다.
ns.filter(i => i*i % 2 == 0).map(i => i*i)
기본적으로, 아무것도는 filter
, map
, flatMap
방법 (즉, 모나드 )를 사용할 수 있습니다
for
대신에 이해 ns
. 좋은 예는 Option monad 입니다. 다음은 동일한 for
명령문이 모나드 List
와 모두에서 작동
하는 이전 예제입니다 Option
.
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))
Slick에서 쿼리는 모나 딕 입니다. 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로 변환합니까?