Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Slick 3.1 multiple joins

Tags:

scala

slick

I'm trying to perform multiple joins in Slick 3.1.1. The result that I would like to achieve is this:

SELECT * FROM customer LEFT JOIN customer_address ON customer.id = customer_address.customer_id LEFT JOIN address ON customer_address.address_id = address.id

I have tried the following:

val query = for {
  c <- Customer
  ca <- CustomerAddress if ca.customerId === c.id
  a <- Address if a.id === ca.addressId
} yield (c, a)

The problem here is that if a customer doesn't have an address that it doesn't appear which makes sense.

Then I tried this:

    val query2 = for {
       (c, ca, a) <- (Customer joinLeft CustomerAddress on (_.id === _.customerId)) joinLeft Address on (_._2.addressId === _.id)
    } yield (c, a)

The problem here is that I get an error on _._2.addressId because _._2 is a Rep object.

Exact error:

Error:(21, 110) value addressId is not a member of slick.lifted.Rep[Option[Models.Tables.CustomerAddress]]
  (c, ca, a) <- (Customer joinLeft CustomerAddress on (_.id === _.customerId)) joinLeft Address on (_._2.addressId === _.id)

Auto generated Slick Tables class: http://pastebin.com/e4M3cGU8

How can I get the results that I want with Slick?

like image 609
Jelle van Es Avatar asked Apr 05 '16 08:04

Jelle van Es


People also ask

What is slick in Scala?

Slick is a Functional Relational Mapping library for Scala that allows us to query and access a database like other Scala collections. We can write database queries in Scala instead of SQL, thus providing typesafe queries.

What types of joins does slick generate?

Slick currently generates implicit joins in SQL ( select ... from a, b where ...) for monadic joins, and explicit joins ( select ... from a join b on ...) for applicative joins. This is subject to change in future versions.

Why doesn't slick support monadic joins like standard SQL?

However, this is not possible in standard SQL, so Slick has to compile them down to applicative joins, which is possible in many useful cases but not in all of them (and there are cases where it is possible in theory but Slick cannot perform the required transformation yet). If a monadic join cannot be properly translated, it will fail at runtime.

What is a cross-join in Scala?

A cross-join is created with a flatMap operation on a Query (i.e. by introducing more than one generator in a for-comprehension): If you add a filter expression, it becomes an inner join: The semantics of these monadic joins are the same as when you are using flatMap on Scala collections.


2 Answers

What you have to do is also map the results.

val query2 = for {
      ((c, ca), a) <- (Customer joinLeft CustomerAddress on (_.id === _.customerId)) joinLeft Address on (_._2.map(_.addressId) === _.id)
} yield (c, a)
like image 155
Tojba Avatar answered Sep 18 '22 08:09

Tojba


This should work. // ((c, ca), a) instead of (c, ca, a)

val query2 = for {
   ((c, ca), a) <- (Customer joinLeft CustomerAddress on (_.id === _.customerId)) joinLeft Address on (_._2.addressId === _.id)
} yield (c, a)
like image 22
TheKojuEffect Avatar answered Sep 18 '22 08:09

TheKojuEffect