[解決済み] scalaのslickメソッド、今ひとつ理解できない。
質問
Slickの動作と必要なものを理解しようとしています。
以下に例を示します。
package models
case class Bar(id: Option[Int] = None, name: String)
object Bars extends Table[Bar]("bar") {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
// This is the primary key column
def name = column[String]("name")
// Every table needs a * projection with the same type as the table's type parameter
def * = id.? ~ name <>(Bar, Bar.unapply _)
}
の目的は何なのか、誰か説明してください。
*
メソッドとは何なのでしょうか?
<>
であるのか、なぜ
unapply
そして、投影法とは何なのか?
~
のインスタンスを返します。
Projection2
?
どのように解決するのですか?
[アップデートのお知らせ]
-
に関する説明を (さらに) 追加しました。
for
に関する説明を追加しました。
-
は
*
メソッドを使用します。これは デフォルトの投影 - というように記述します。
「すべての列(または計算された値)を私は 通常 に興味がある'。
テーブルは複数のフィールドを持つことができます。 デフォルトプロジェクションのためのサブセットだけが必要です。デフォルトの投影は、テーブルの型パラメータと一致する必要があります。 パラメータと一致しなければなりません。
一つずつ見ていきましょう。がなければ
<>
のものだけで*
:// 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
? それはQuery
を投影したもので(String, Int)
. 呼び出されたとき、それはList
の(String, Int)
のタプルを投影します。val result: List[(String, Int)] = q.list
この場合、必要なプロジェクションを
yield
節で定義しています。 のfor
理解することができます。 -
今、約
<>
とBar.unapply
.これは、以下のようなものを提供します。 地図投影 .
これまで、slickを使うとScalaでどのようにクエリーを表現できるかを見てきました。 を返すクエリをScalaで表現できることを見てきました。 カラムの投影 (または計算値)を返すクエリをScalaで表現できることを見てきました。 これらのクエリ を実行する場合、結果の行を考えなければなりません。 クエリの をScalaのタプルとして考えなければなりません。 . タプルの型は、(
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 }
タプルを扱うので、カラムが多すぎると面倒になるかもしれません。 カラムが多すぎると面倒になります。私たちは結果を
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
. 2つの引数Bar, Bar.unapply _
はslickにこの(Int, String)
の投影がどのようにケースクラスにマッピングされなければならないかを教えてください。これは双方向のマッピングです。
Bar
はケースクラスのコンストラクタで、これは に必要な情報です。(id: Int, name: String)
からBar
. そしてunapply
はその逆です。どこが
unapply
はどこから来るのでしょうか? これは Scala の標準的なメソッドで、普通の case class で利用可能です。 を定義するだけで、普通の case class で利用できます。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
. 呼び出されたとき、それはList
のBaz
オブジェクトのval result: List[Baz] = q1.list
-
最後に、余談ですが
.?
が提供する オプション解除 - というScalaの方法です。 でない値を扱うことができます。(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
の内包を使用する方法についてのコメントに対するものです。どういうわけか、モナドはいつも現れ、説明の一部を要求してきます。 説明の一部であることを要求します...
内包はコレクションだけに特化したものではありません。 どのような種類の モナド で使用することができ、コレクションは はScalaで利用できる多くの種類のモナド型のうちの1つだけです。
しかし、コレクションは身近なものなので、説明のための良い出発点になります。
しかし、コレクションは身近なものなので、説明の良い出発点になります。
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, ...)
Scalaでは、for comprehensionは以下のような構文上の糖分です。 メソッド(ネストされた可能性のある)呼び出しのための構文解析です。上記のコード とは(多かれ少なかれ)等価です。
ns.filter(i => i*i % 2 == 0).map(i => i*i)
基本的に
filter
,map
,flatMap
メソッド(言い換えれば モナド ) はfor
の代わりにns
. 良い例として は オプションモナド . これは前の例です ここで、同じfor
ステートメントがList
と同様にOption
のモナドもあります。// (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では、クエリはモナド(単項演算子)です。 を持つオブジェクトです。
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
の繰り返し変換によりQuery(Bars)
の各呼び出しでfilter
とmap
. コレクションの場合 コレクションでは、これらのメソッドは実際にコレクションを反復処理し、フィルタリングします。 しかし、SlickではSQLを生成するために使用されます。詳しくはこちら。 Scala SlickはどのようにScalaのコードをJDBCに変換するのですか?
関連
-
[解決済み] scalaは推論される型の「許容される複雑さ」にどのような制限を設けているのでしょうか?
-
[解決済み] ジッパーがコモナドである理由を理解する
-
[解決済み] Scala の Case Classes のオーバーロード・コンストラクタ?
-
[解決済み] Apache SparkでDataframeのカラム値をListとして抽出する。
-
[解決済み] Scalaにおけるparam: _*の意味とは?
-
[解決済み] Scalaのcaseクラスを宣言することのデメリットは何ですか?
-
[解決済み] SBTのrunアクションでアプリケーションを実行するために、JVMの最大ヒープサイズを"-Xmx "で指定する方法は?
-
[解決済み] Scalaで、リストから重複を取り除くにはどうしたらいいですか?
-
[解決済み] なぜScalaのimmutable Setは型が共変しないのか?
-
[解決済み] ScalaにおけるNull/Nothing/Unitの使用法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Scalaです。リスト[Future]からFuture[List]への変換は、失敗したFutureを無視する。
-
[解決済み] Any、AnyVal、AnyRef、Objectの関係と、Javaコードでのマッピングについて教えてください。
-
[解決済み] Scalaのアクター:受信と反応
-
[解決済み] Scalaでサブアレイを取得する正しい方法は何ですか?
-
[解決済み] なぜ `private val` と `private final val` は違うのですか?
-
[解決済み] 関数型プログラミング(特にScalaとScala API)におけるreduceとfoldLeft/foldの違いとは?
-
[解決済み] アブストラクトオーバーとはどういう意味ですか?
-
[解決済み] タプルのリストをマップに変換する (重複するキーに対処する?)
-
[解決済み] パッケージオブジェクト
-
[解決済み] Scalaの場合 クラス継承