Not me
Not me

Reputation: 139

Scala Slick value foreach is not a member of

This is in a Scala Play project using to connect to MariaDB.

cat build.sbt
...
jdbc,
"org.mariadb.jdbc" % "mariadb-java-client" % "2.6.2",
"com.typesafe.slick" %% "slick" % "3.3.2",
...
class Users(tag: Tag) extends Table[(...)](tag, "USERS") {...}

val users = TableQuery[Users]

for (u <- users) {...}

Error:

value foreach is not a member of slick.lifted.TableQuery[controller.Users]

for (u <- users) {
          ^

I tried adding .result to users in the for loop, but I got

value foreach is not a member of slick.jdbc.MySQLProfile.StreamingProfileAction[Seq[controller.Users#TableElementType],controller.Users#TableElementType,slick.dbio.Effect.Read]

for (u <- users.result) {
                ^

I don't have db.run anywhere in the code.

Upvotes: 0

Views: 1221

Answers (1)

Richard Dallaway
Richard Dallaway

Reputation: 4330

It looks like you want to iterate over the users in your database.

There are a couple of concepts that you need here:

  • The expression users is a kind of query. Methods like map and filter are a way to produce alternative queries. Iterating over a query, with a foreach, doesn't really make sense.

  • With users.results you have an action (a kind of DBIOAction). This is something you might send to the database, with a db.run. Again, methods like map or flatMap are a way to convert and combine actions, but iterating over an action with foreach, doesn't really make sense.

So what to do? The signature of users.result is something like DBIO[Seq[User]]. If you want to do something to each user, maybe print them out, you can construct an action to do that. One way is to map the result of the action (a list of users) to something else. Maybe:

val doSomethingWithEachUser: DBIO[Unit] = 
  users.result.map { seqUsers => 
    seqUsers.foreach(println)
  }

Here we've used map to change the result type of the DBIO[Seq[User]] into a DBIO[Unit].

You can then send doSomethingWithEachUser to the database (so to speak) with db.run. When you do that, your action is run, and when the values are available, the println will happen.

To switch back to a for comprehension, you can see that we need to construct a new action:

val doSomethingWithEachUser: DBIO[Unit] =
  for {
    allUsers <- messages.result
  } yield allUsers.foreach(println)

...for example.

The next layer on would be in Future, which is the result from db.run. You could also use a map (or similar) on a future to work with the data. Slick is pretty much all about these kinds of building blocks of queries, actions, and (finally) futures, and manipulating them with combinators like map and flatMap.

Upvotes: 1

Related Questions