k47.cz    — každý den dokud se vám to nezačne líbit
foto Praha výběr povídky kultura | twitter FB


ScalaQuery

23. 6. 2011 — k47 (CC by)

Před nějakou dobou jsem porovnával for expression ze Scaly a LINQ z C# a došel jsem k závěru, že for comprehension umí skoro všechno, co LINQ. Jednoduchému for conprehenshion zcela nepřekvapivě chybí konstrukce pro pohodlné provádění operací jako group by, order by a samozřejmě obdoba LINQ to SQL, což je kompletní ORM.

For comprehension je konstrukce pro kompozici monád, takže není principiálně nemožné, vytvořit a skládat takové monády, které budou vykonávat všechny potřebné operace.

ScalaQuery je knihovna pro typově bezpečný přístup k relační databázi, která šikovně využívá právě for comprehension a je plně srovnatelná s LINQ.


Rozdíly oproti LINQ to SQL:


(Většina následujících ukázek pochází z wiki projektu)

Definice tabulek

object Users extends Table[(Int, String, Option[String])]("users") {
  def id    = column[Int]           ("id", O NotNull)
  def first = column[String]        ("first", O Default "NFN", O DBType "varchar(64)")
  def last  = column[Option[String]]("last")
  def * = id ~ first ~ last
}

object Orders extends Table[(Int, Int, String, Boolean, Option[Boolean])]("orders") {
  def userID  = column[Int]("userID", O NotNull)
  def orderID = column[Int]("orderID", O NotNull)
  def product = column[String]("product")
  def shipped = column[Boolean]("shipped", O Default false, O NotNull)
  def rebate  = column[Option[Boolean]]("rebate", O Default Some(false))
  def * = userID ~ orderID ~ product ~ shipped ~ rebate

  def user = foreignKey("user_fk", userID, Users)(_.id)
}

Jednoduché selecty

for (u <- Users) yield u.*
SELECT * FROM users

for {
  u <- Users if u.first === "Stefan"
} yield u.id ~ u.last
SELECT id, last FROM users WHERE first = 'Stefan'

Count

(for (u <- Users) yield u.*).count            // SELECT count(*) FROM users

for (u <- Users) yield u.first.count         // SELECT count(first) FROM users

for (u <- Users) yield u.first.countDistinct // SELECT count(distinct first) FROM users

Implicitní join se vytvoří zřetězením více generátorů

for {
  u <- Users
  o <- Orders if o.userID is u.id
} yield u.first ~ o.orderID
SELECT u.first, u.orderID FROM users u, orders o WHERE u.id = o.userID

Explicitní join

for {
  Join(u, o) <- Users innerJoin Orders on (_.id is _.userID)
} yield u.first ~ o.orderID
SELECT u.first, u.orderID FROM users u JOIN orders o ON u.id = o.userID

Join přes cizí klíč

for {
  o <- Orders if o.shipped === true
  u <- o.user
} yield u.first ~ o.product

Explicitní outer join

for {
  Join(u, o) <- Users leftJoin Orders on (_.id is _.userID)
} yield u.first ~ o.orderID.?

Group by

for {
  o <- Orders
  u <- o.user
  _ <- Query groupBy u.id
} yield u.first.min.get ~ o.orderID.count

PS: Matin Odersky se na Scala Exchange 2011 letmo zmínil, že knihovna pro přístup k databázím a externím datovým zdrojům podobná ScalaQuery se v rámci projektu slick chystá přímo do nějaké budoucí verze Scaly

PS2: Krátce po publikování článku jsem se dozvěděl o Scala Integrated Query - ScalaQuery + nějaké zajímavé funkce navíc. (via @ijuma)

vstoupit do diskuze    sdílet na facebooku, twitteru, google+

štítky: #programování «« »» #obsah «« »» #programování #Scala #C-sharp #LINQ

publikováno 23. 6. 2011

příbuzné články:
Scala for expression vs. C# LINQ
Scala - trait Dynamic 📷
Scala - typově bezpečné eventy 📷
Scala type bounds vs. C# constraints on type parameters 📷
Scala versus C# 4.0 - Strukturální typy versus Dynamic member lookup 📷
Kompozice monád & Option 📷

sem odkazují:
Scala - konverze TupleN na case class 📷
Projekt Chanminer - implementace
Co je dneska k večeři? Zase Scala!

píše k47 & hosté, ascii@k47.cz